diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 204badef5..44f51a8bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,19 +27,11 @@ jobs: fail-fast: false matrix: version: - - '1.6' # LTS (minimal declared julia compat in `Project.toml`) - - '1.8' # latest stable - os: [ubuntu-latest, windows-latest, macos-latest] + - '1.8.2' # latest stable + - '1.8.1' # known good + - 'nightly' + os: [windows-latest] arch: [x64] - include: - - os: ubuntu-latest - prefix: xvfb-run # julia-actions/julia-runtest/blob/master/README.md - - os: ubuntu-latest - prefix: xvfb-run - version: '1.7' # only test intermediate relase on `ubuntu` - # - os: ubuntu-latest - # prefix: xvfb-run - # version: 'nightly' steps: - uses: actions/checkout@v3 @@ -49,52 +41,13 @@ jobs: - uses: julia-actions/cache@v1 - uses: julia-actions/julia-buildpkg@latest - - name: Test upstream RecipesBase - shell: julia --project=@. --color=yes {0} - run: | - using Pkg; Pkg.develop(path="RecipesBase"); Pkg.test("RecipesBase") - - - name: Test upstream RecipesPipeline - shell: julia --project=@. --color=yes {0} - run: | - using Pkg; Pkg.develop(path="RecipesPipeline"); Pkg.test("RecipesPipeline") - - - name: PyPlot dependencies - shell: julia --project=@. --color=yes {0} - run: | - @show ENV["PYTHON"] - using Pkg - Pkg.add("Conda"); Pkg.build("Conda"; verbose=true) - using Conda; env, rc = Conda.ROOTENV, Conda.conda_rc(Conda.ROOTENV) - Conda.runconda(`config --set auto_update_conda False --file $rc --force`, env) - Pkg.add("PyCall"); Pkg.build("PyCall"; verbose=true) - Conda.add("matplotlib") - Conda.list() - - - name: Ubuntu LaTeX dependencies - if: startsWith(matrix.os, 'ubuntu') - run: | - sudo apt-get -y update - sudo apt-get -y install gnuplot poppler-utils texlive-{latex-base,latex-extra,luatex} - sudo fc-cache -vr - - uses: julia-actions/julia-runtest@latest with: prefix: ${{ matrix.prefix }} # for `xvfb-run` - - name: Run downstream tests - if: startsWith(matrix.os, 'ubuntu') - shell: xvfb-run julia --project=@. --color=yes {0} - run: | - using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots") - using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes") - - - uses: julia-actions/julia-processcoverage@latest - if: startsWith(matrix.os, 'ubuntu') - - uses: codecov/codecov-action@v3 - if: startsWith(matrix.os, 'ubuntu') - with: - file: lcov.info + - name: Setup tmate session + if: ${{ failure() && matrix.version == '1.8.2' }} + uses: mxschmitt/action-tmate@v3 Skip: if: contains(github.event.head_commit.message, '[skip ci]') diff --git a/src/backends/gr.jl b/src/backends/gr.jl index ce1c39868..6e9b534a0 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -691,7 +691,7 @@ function gr_display(plt::Plot, dpi_factor = 1) viewport_canvas[1] *= ratio viewport_canvas[2] *= ratio end - + @debug viewport_canvas # fill in the viewport_canvas background gr_fill_viewport(viewport_canvas, plt[:background_color_outside]) @@ -703,6 +703,99 @@ function gr_display(plt::Plot, dpi_factor = 1) GR.updatews() end +# A stream.jl change in Base between 1.8.1 and 1.8.2 ? +function Base.uv_readcb(handle::Ptr{Cvoid}, nread::Cssize_t, buf::Ptr{Cvoid}) + stream_unknown_type = Base.@handle_as handle Base.LibuvStream + nrequested = ccall(:jl_uv_buf_len, Csize_t, (Ptr{Cvoid},), buf) + function readcb_specialized(stream::Base.LibuvStream, nread::Int, nrequested::UInt) + lock(stream.cond) + if nread < 0 + if nread == Base.UV_ENOBUFS && nrequested == 0 + # remind the client that stream.buffer is full + notify(stream.cond) + elseif nread == Base.UV_EOF # libuv called uv_stop_reading already + if stream.status != Base.StatusClosing + stream.status = Base.StatusEOF + if stream isa Base.TTY # TODO: || ccall(:uv_is_writable, Cint, (Ptr{Cvoid},), stream.handle) != 0 + # stream can still be used either by reseteof # TODO: or write + notify(stream.cond) + else + # underlying stream is no longer useful: begin finalization + ccall(:jl_close_uv, Cvoid, (Ptr{Cvoid},), stream.handle) + stream.status = Base.StatusClosing + end + end + else + stream.readerror = Base._UVError("read", nread) + # This is a fatal connection error + ccall(:jl_close_uv, Cvoid, (Ptr{Cvoid},), stream.handle) + stream.status = Base.StatusClosing + end + else + Base.notify_filled(stream.buffer, nread) + notify(stream.cond) + end + unlock(stream.cond) + + # Stop background reading when + # 1) there's nobody paying attention to the data we are reading + # 2) we have accumulated a lot of unread data OR + # 3) we have an alternate buffer that has reached its limit. + if stream.status == Base.StatusPaused || + (stream.status == Base.StatusActive && + ((bytesavailable(stream.buffer) >= stream.throttle) || + (bytesavailable(stream.buffer) >= stream.buffer.maxsize))) + # save cycles by stopping kernel notifications from arriving + ccall(:uv_read_stop, Cint, (Ptr{Cvoid},), stream) + stream.status = Base.StatusOpen + end + nothing + end + readcb_specialized(stream_unknown_type, Int(nread), UInt(nrequested)) + nothing +end + +function Base.create_expr_cache(pkg::Base.PkgId, input::String, output::String, concrete_deps::typeof(Base._concrete_dependencies), internal_stderr::IO = stderr, internal_stdout::IO = stdout) + @nospecialize internal_stderr internal_stdout + rm(output, force=true) # Remove file if it exists + depot_path = map(abspath, Base.DEPOT_PATH) + dl_load_path = map(abspath, Base.DL_LOAD_PATH) + load_path = map(abspath, Base.load_path()) + path_sep = Sys.iswindows() ? ';' : ':' + any(path -> path_sep in path, load_path) && + error("LOAD_PATH entries cannot contain $(repr(path_sep))") + + deps_strs = String[] + function pkg_str(_pkg::Base.PkgId) + if _pkg.uuid === nothing + "Base.PkgId($(repr(_pkg.name)))" + else + "Base.PkgId(Base.UUID(\"$(_pkg.uuid)\"), $(repr(_pkg.name)))" + end + end + for (pkg, build_id) in concrete_deps + push!(deps_strs, "$(pkg_str(pkg)) => $(repr(build_id))") + end + deps_eltype = sprint(show, eltype(concrete_deps); context = :module=>nothing) + deps = deps_eltype * "[" * join(deps_strs, ",") * "]" + trace = isassigned(Base.PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])` : `` + io = open(pipeline(`$(Base.julia_cmd()::Cmd) -O0 + --output-ji $output --output-incremental=yes + --startup-file=no --history-file=no --warn-overwrite=yes + --color=$(Base.have_color === nothing ? "auto" : Base.have_color ? "yes" : "no") + $trace + -`, stderr = internal_stderr, stdout = internal_stdout), + "w", stdout) + # write data over stdin to avoid the (unlikely) case of exceeding max command line size + write(io.in, """ + Base.include_package_for_output($(pkg_str(pkg)), $(repr(abspath(input))), $(repr(depot_path)), $(repr(dl_load_path)), + $(repr(load_path)), $deps, $(repr(Base.source_path(nothing)))) + """) + close(io.in) + return io +end + + function gr_set_tickfont(sp, letter) axis = sp[get_attr_symbol(letter, :axis)] gr_set_font( @@ -2181,7 +2274,7 @@ for (mime, fmt) in ( "application/postscript" => "ps", "image/svg+xml" => "svg", ) - @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend}) + @eval function Plots._show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend}) GR.emergencyclosegks() dpi_factor = $fmt == "png" ? plt[:dpi] / Plots.DPI : 1 filepath = tempname() * "." * $fmt @@ -2190,9 +2283,14 @@ for (mime, fmt) in ( "GKS_ENCODING" => "utf8", "GKSwstype" => $fmt, ) do + @debug ENV["GKS_FILEPATH"] gr_display(plt, dpi_factor) GR.emergencyclosegks() + @debug filepath end + sleep(5) + #open(filepath, "w") do f + #end # creating an empty file allows precompilation to proceed write(io, read(filepath, String)) rm(filepath) end diff --git a/src/precompilation.jl b/src/precompilation.jl index e4f4e9e0d..f72b2d0df 100644 --- a/src/precompilation.jl +++ b/src/precompilation.jl @@ -1,37 +1,5 @@ -using SnoopPrecompile - if get(ENV, "PLOTS_PRECOMPILE", "true") == "true" - @precompile_setup begin - n = length(_examples) - imports = sizehint!(Expr[], n) - examples = sizehint!(Expr[], 10n) - for i in setdiff(1:n, _backend_skips[:gr], _animation_examples) - _examples[i].external && continue - (imp = _examples[i].imports) === nothing || push!(imports, imp) - func = gensym(string(i)) - push!(examples, quote - $func() = begin # evaluate each example in a local scope - # @show $i # debug - $(_examples[i].exprs) - if $i == 1 # only for one example - fn = tempname() - pl = current() - gui(pl) - Sys.iswindows() || savefig(pl, "$fn.png") - Sys.iswindows() || savefig(pl, "$fn.pdf") - end - nothing - end - $func() - end) - end - withenv("GKSwstype" => "nul") do - @precompile_all_calls begin - eval.(imports) - gr() - eval.(examples) - # eventually eval for another backend ... - end - end - end + pl = plot(Plots.fakedata(50, 5), w = 3) + fn = tempname() + savefig(pl, "$fn.png") end