Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with zip #115

Open
claell opened this issue Oct 10, 2023 · 21 comments
Open

Problem with zip #115

claell opened this issue Oct 10, 2023 · 21 comments

Comments

@claell
Copy link

claell commented Oct 10, 2023

See https://tex.stackexchange.com/questions/698165/tex4ebook-error.

I don't know what causes the error for me.

When I run tex4ebook on a project, I get the following error:

tex4ebook -f epub3 generated-latex.tex
[STATUS]  tex4ebook: Conversion started
[STATUS]  tex4ebook: Input file: generated-latex.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
Der Befehl "tidy" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
[WARNING] exec_epub: tidy command seems missing, you should install it in order
  to make valid epub file

zip error: Internal logic error (fstat(stdin))
...023/texmf-dist/scripts/tex4ebook/tex4ebook-exec_epub.lua:295: exit
C:\texlive\2023\bin\windows\runscript.tlu:921: command failed with exit code 1:
texlua c:\texlive\2023\texmf-dist\scripts\tex4ebook\tex4ebook -f epub3 generated-latex.tex
@michal-h21
Copy link
Owner

Could you try to install the development version of tex4ebook? I think I had similar bug report recently and changed the way how the zip command is handled. I hope this fix would work also for you.

@claell
Copy link
Author

claell commented Oct 10, 2023

Is that possible through tlmgr? Could you give a short hint, how to do that?

@michal-h21
Copy link
Owner

No, it is possible only using this guide: https://github.com/michal-h21/tex4ebook/blob/master/INSTALL.md

@claell
Copy link
Author

claell commented Oct 10, 2023

Got it, thanks for referencing it. I am on Windows, so will need to take a closer look (hopefully tomorrow if I have time).

@claell
Copy link
Author

claell commented Oct 11, 2023

Mh, that guide seems to be bound to certain ways of compiling a tex file.

What I did, before, was executing tex4ebook from the command line.

I also tried making on Windows, but that seems to fail.

Also, executing the lua file directly in the command line doesn't work for me.

There should be a way how to do this, right? In the end, the guide also only seems to link a lua file (tex4ebook.lua, which doesn't exist anymore in master) to the chain, right?

@claell
Copy link
Author

claell commented Oct 11, 2023

Ah, I made progress. I need to use the tex4ebook file without any extension, as that is in fact a lua file (without an extension).

@claell
Copy link
Author

claell commented Oct 11, 2023

I think, I got it to work like the following (if this is not correct, please tell me; if this is correct, I had appreciated a short explanation how to do this right away, as the linked guide for Windows is overly complicated and doesn't really tell what to do):

texlua.exe .\tex4ebook\tex4ebook .\test.tex
[STATUS]  tex4ebook: Conversion started
[STATUS]  tex4ebook: Input file: .\test.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
Der Befehl "tidy" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
[WARNING] exec_epub: tidy command seems missing, you should install it in order
  to make valid epub file

zip error: Internal logic error (fstat(stdin))
...023/texmf-dist/scripts/tex4ebook/tex4ebook-exec_epub.lua:295: exit

Error is still there.

@claell
Copy link
Author

claell commented Oct 11, 2023

And interestingly, different error when running from within the tex4ebook folder:

texlua.exe .\tex4ebook ..\test.tex
[STATUS]  tex4ebook: Conversion started
[STATUS]  tex4ebook: Input file: ..\test.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
Der Befehl "tidy" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
[WARNING] exec_epub: tidy command seems missing, you should install it in order
  to make valid epub file

zip error: Internal logic error (fstat(stdin))
        1 Datei(en) kopiert.
[STATUS]  tex4ebook: Conversion finished

There I get a finished status message. Also, the EPUB seems to be created with that method (just in the tex4ebook folder in that case).

Possibly, that gives some hint to what the problem is?

@michal-h21
Copy link
Owner

This seems like an issue with the zip command. On line 295 in tex4ebook-exec_epub.lua, we test if the zip command exists, because on MikTeX they use a different name for this command. What result do you get when you run zip -v on the command line? Does it fail with error? It should print version info.

Anyway, you can try to avoid the command detection and select zip directly using this version of tex4ebook-exec_epub.lua:

module(...,package.seeall)
local lfs = require("lfs")
local os = require("os")
local io = require("io")
local log = logging.new("exec_epub")
--local ebookutils = require("ebookutils")
local ebookutils = require "mkutils"
local dom = require("luaxml-domobject")
local outputdir_name="OEBPS"
local metadir_name = "META-INF"
local mimetype_name="mimetype"
outputdir=""
outputfile=""
outputfilename=""
-- the directory where the epub file should be moved to
destdir=""
basedir = ""
tidy = false
local include_fonts = false
local metadir=""

-- from https://stackoverflow.com/a/43407750/2467963
local function deletedir(dir)
  local attr = lfs.attributes(dir)
  if attr then
    for file in lfs.dir(dir) do
        local file_path = dir..'/'..file
        if file ~= "." and file ~= ".." then
            if lfs.attributes(file_path, 'mode') == 'file' then
                os.remove(file_path)
                log:info('remove file',file_path)
            elseif lfs.attributes(file_path, 'mode') == 'directory' then
                log:info('dir', file_path)
                deletedir(file_path)
            end
        end
    end
    lfs.rmdir(dir)
  end
  log:info('remove dir',dir)
end

function prepare(params)
	local makedir= function(path)
		local current = lfs.currentdir()
		local dir = ebookutils.prepare_path(path .. "/")
		if type(dir) == "table" then
			local parts,msg =  ebookutils.find_directories(dir)
			if parts then 
			 ebookutils.mkdirectories(parts)
		  end
		end
		lfs.chdir(current)
	end
	basedir = params.input.."-".. params.format
	outputdir= basedir.."/"..outputdir_name
  deletedir(basedir)
	makedir(outputdir)
	metadir = basedir .."/" .. metadir_name 
	makedir(metadir)
  if params.outdir ~= "" then
    destdir = params.outdir .. "/"
    makedir(destdir)
  end
	mimetype= basedir .. "/" ..mimetype_name --os.tmpname()
	tidy = params.tidy
	include_fonts = params.include_fonts
	params["t4ht_par"] = params["t4ht_par"] -- + "-d"..string.format(params["t4ht_dir_format"],outputdir)
  params.tex4ht_sty_par = params.tex4ht_sty_par .. ",uni-html4"
	params.config_file.Make.params = params
  local mode = params.mode
	if params.config_file.Make:length() < 1 then
    if mode == "draft" then
      params.config_file.Make:htlatex()
    else
      params.config_file.Make:htlatex()
      params.config_file.Make:htlatex()
      params.config_file.Make:htlatex() 
    end
	end
	if #params.config_file.Make.image_patterns > 0 then
		params["t4ht_par"] = params["t4ht_par"] .." -p"
	end
	params.config_file.Make:tex4ht()
	params.config_file.Make:t4ht()
  -- do some cleanup
  params.config_file.Make:match("tmp$",function(filename, par)
    -- detect if a tmp file was created for content from STDIN
    if par.is_tmp_file then
      -- and remove it
      log:info("Removing temporary file", par.tex_file)
      os.remove(par.tex_file)
    end
  end)
	return(params)
end

function run(out,params)
	--local currentdir=
	outputfilename=out
	outputfile = outputfilename..".epub"
	log:info("Output file: "..outputfile)
	--lfs.chdir(metadir)
	local m= io.open(metadir.."/container.xml","w")
	m:write([[
<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="OEBPS/content.opf"
media-type="application/oebps-package+xml"/>
</rootfiles>
</container>
	]])
	m:close()
	--lfs.chdir("..")
	m=io.open(mimetype,"w")
	m:write("application/epub+zip")
	m:close()
	params.config_file.Make:run()
	--[[for k,v in pairs(params.config_file.Make) do
		print(k.. " : "..type(v))
	end--]]
  --print(os.execute(htlatex_run))
end

local mimetypes = {
	css = "text/css",
	png = "image/png", 
	jpg = "image/jpeg",
	jpeg = "image/jpeg",
	gif = "image/gif",
	svg = "image/svg+xml",
	html= "application/xhtml+xml",
	xhtml= "application/xhtml+xml",
	ncx = "application/x-dtbncx+xml",
	otf = "application/font-sfnt",
	ttf = "application/font-sfnt",
	woff = "application/font-woff",
	woff2 = "font/woff2",
  js = "text/javascript",
  mp3 = "audio/mpeg",
  mp4 = "audio/mp4",
  avi = "video/x-msvideo",
  mkv = "video/x-matroska",
  smil = "application/smil+xml",
  pls = "application/pls+xml"
}

function remove_empty_guide(content)
  return content:gsub("<guide>%s*</guide>","")
end



function make_opf()
	-- Join files content.opf and content-part2.opf
	-- make item record for every converted image
	local lg_item = function(item)
		-- Find mimetype and make item tag for each converted file in the lg file
		local fname,ext = item:match("([^%/^%.]*)%.([%a%d]*)$")
    if not ext then return nil end
    local lower_ext = string.lower(ext)
		local mimetype = mimetypes[lower_ext] or ""
		if mimetype == "" then log:info("Mimetype for the  "..ext.." extension is not registered"); return nil end
		local dir_part = item:split("/")
		table.remove(dir_part,#dir_part)
		local id=table.concat(dir_part,"-")..fname.."_"..ext
    -- remove invalid characters from id start
    id = id:gsub("^[%.%-]*","")
    -- remove colons
    id = id:gsub("[:%(%)]", "_")
    -- id cannot start by number, add trailing "x" character
    id = id:gsub("^([%d])", "x%1")
		return "<item id='"..id .. "' href='"..item.."' media-type='"..mimetype.."' />",id
	end
	local find_all_files= function(s,r)
    -- find files that had been declared in the OPF file using \Configure{OpfMetadata}
		local r = r or "(.*)%.([x]?html)"
		local files = {}
		for item in s:gmatch("href=\"(.-)\"") do
      local i, ext = item:match(r)
      if i then
        --local i, ext = s:match(r)-- do
        ext = ext or "true"
        files[item] = ext 
      end
		end 
		return files
	end
	local tidyconf = nil
	if tidy then 
		tidyconf = kpse.find_file("tex4ebook-tidyconf.conf")
	end
	--local opf_first_part = outputdir .. "/content.opf" 
	local opf_first_part =   "content.opf" 
	local opf_second_part =  "content-part2.opf"
	--local opf_second_part = outputdir .. "/content-part2.opf"
	if 
		ebookutils.file_exists(opf_first_part) and ebookutils.file_exists(opf_second_part) 
	then
    local h_first  = io.open(opf_first_part,"r")
    local h_second = io.open(opf_second_part,"r")
    local opf_complete = {}
    table.insert(opf_complete,h_first:read("*all"))
    -- we used to detect all declared HTML files, but this table wasn't used anymore, so I deprecate this use
    -- local used_html = find_all_files(opf_complete[1])
    -- local lg_file = ebookutils.parse_lg(outputfilename..".lg")
    -- The lg_file has been already loaded by make4ht, it doesn't make sense to load it again
    -- Furthermore, it is now possible to add new files from Lua build files
    local lg_file = Make.lgfile  or ebookutils.parse_lg(outputfilename..".lg")
    local used_files = {}
    for _,filename in ipairs(lg_file["files"]) do
      -- we need to test the filenames in order to prevent duplicates
      used_files[filename] = true
    end
    local outside_spine = {}
    local all_used_files = find_all_files(opf_complete[1],"(.+)%.(.+)")
    local used_paths = {}
    local used_ids   = {}
    for _,k in ipairs(lg_file["files"]) do
      local ext = k:match("%.([%a%d]*)$")
      local parts = k:split "/"
      local fn = parts[#parts]
      local allow_in_spine =  {html="",xhtml = "", xml = ""}
      table.remove(parts,#parts)
      --table.insert(parts,1,"OEBPS")
      table.insert(parts,1,outputdir)
      local item,id = lg_item(k) 
      if item then
        local path = table.concat(parts)
        if not used_paths[path] then
          ebookutils.mkdirectories(parts)
          used_paths[path]=true
        end
        if allow_in_spine[ext] and tidy then 
          if tidyconf then
            log:info("Tidy: "..k)
            local run ="tidy -c  -w 200 -q -utf8 -m -config " .. tidyconf .." " .. k
            os.execute(run) 
          else
            log:info "Tidy: Cannot load tidyconf.conf"
          end
        end
        if not used_ids[id] then    
          ebookutils.copy(k, outputdir .. "/"..k)
          if not all_used_files[k] then
            table.insert(opf_complete,item)
            if allow_in_spine[ext] then 
              table.insert(outside_spine,id)
            end
          end
        end
        used_ids[id] = true
      end
    end
    for _,f in ipairs(lg_file["images"]) do
      local f = f.output
      local p, id = lg_item(f)
      -- process the images only if they weren't registered in lg_file["files"]
      -- they would be processed twice otherwise
      if not used_files[f] and not used_ids[id] then
        ebookutils.copy(f, outputdir .. "/"..f)
        table.insert(opf_complete,p)
      end
      used_ids[id] = true
    end
    local end_opf = h_second:read("*all")
    local spine_items = {}
    for _,i in ipairs(outside_spine) do
      table.insert(spine_items,
      '<itemref idref="${idref}" linear="no" />' % {idref=i})
    end
    table.insert(opf_complete,end_opf % {spine = table.concat(spine_items,"\n")})
    h_first:close()
    h_second:close()
    h_first = io.open(opf_first_part,"w")
    local opf_completed = table.concat(opf_complete,"\n")
    -- poor man's tidy: remove trailing whitespace befora xml tags
    opf_completed = opf_completed:gsub("[ ]*<","<")
    opf_completed = remove_empty_guide(opf_completed)
    h_first:write(opf_completed)
    h_first:close()
    os.remove(opf_second_part)
    --ebookutils.copy(outputfilename ..".css",outputdir.."/")
    ebookutils.copy(opf_first_part,outputdir.."/"..opf_first_part)
    --for c,v in pairs(lg_file["fonts"]) do
    --	print(c, table.concat(v,", "))
    --end
    --print(table.concat(opf_complete,"\n"))
  else
    log:warning("Missing opf file")
  end
end
local function find_zip()
  return "zip"
end

function pack_container()
  local ncxfilename = outputdir .. "/" .. outputfilename .. ".ncx"
  if os.execute("tidy -v") > 0 then
    log:warning("tidy command seems missing, you should install it" ..
    " in order\n  to make valid epub file") 
    log:info("Using regexp based cleaning")
    local lines = {}
    for line in io.lines(ncxfilename) do
      local content = line:gsub("[ ]*<","<")
      if content:len() > 0 then
        table.insert(lines, content)
      end
    end
    table.insert(lines,"")
    local ncxfile = io.open(ncxfilename,"w")
    ncxfile:write(table.concat(lines,"\n"))
    ncxfile:close()
  else
    log:info("Tidy ncx "..
    os.execute("tidy -xml -i -q -utf8 -m " ..  ncxfilename))
    log:info("Tidy opf "..
    os.execute("tidy -xml -i -q -utf8 -m " .. 
    outputdir .. "/" .. "content.opf"))
  end
  local zip = find_zip()
  -- we need to remove the epub file if it exists already, because it may contain files which aren't used anymore
  if ebookutils.file_exists(outputfile) then os.remove(outputfile) end
  log:info("Pack mimetype " .. os.execute("cd "..basedir.." && "..zip.." -q0X "..outputfile .." ".. mimetype_name))
  log:info("Pack metadir "   .. os.execute("cd "..basedir.." && "..zip.." -qXr9D " .. outputfile.." "..metadir_name))
  log:info("Pack outputdir " .. os.execute("cd "..basedir.." && "..zip.." -qXr9D " .. outputfile.." "..outputdir_name))
  log:info("Copy generated epub ")
  ebookutils.cp(basedir .."/"..outputfile, destdir .. outputfile)
end

local function update_file(filename, fn)
  -- update contents of a filename using function
  local f = io.open(filename, "r")
  local content = f:read("*all")
  f:close()
  local newcontent = fn(content)
  local f = io.open(filename, "w")
  f:write(newcontent)
  f:close()
end

local function fix_ncx_toc_levels(dom)
  -- OK, this is a weird hack. The problem is that when \backmatter
  -- follows \part, the subsequent chapters are listed under part 
  -- in the NCX TOC
  -- I've added special element <navmark> to the ncx file to detect mark numbers.
  -- chapters in backmatter should have empty mark number

  -- get current <navpoint> section type and mark number
  local get_navpoint_info = function(navpoint)
    local navmarks = navpoint:query_selector("navmark")
    if navmarks and #navmarks > 0 then
      -- we are interested only in the first navmark, because it contains the current navPoint info
      local navmark = navmarks[1]
      return navmark:get_attribute("type"), navmark:get_text()
    end
    return nil, "Cannot find navLabel"
  end

  local fix_chapters = function(part)
    -- move chapters from backmatter and appendix from the current part
    -- find part position in the element list, it will be place where backmatter will be moved
    local part_pos = part:find_element_pos() + 1
    local part_parent = part:get_parent()
    -- child chapters
    local children = part:get_children()
    -- loop over children from back, where backmatter or appendix may be placed
    for i = #children, 1, -1 do
      local current = children[i]
      local sect_type, mark = get_navpoint_info(current)
      if sect_type then
        -- remove spaces from mark
        mark = mark:gsub("%s", "") 
        if sect_type == "appendix" or (sect_type == "chapter" and mark=="") then
          -- move chapter at the same level as part, after part
          -- the correct order will be kept, because we move from the back of the node list
          -- and every new node is placed before previous added nodes
          part_parent:add_child_node(current:copy_node(), part_pos)
          current:remove_node()
        else
          -- break processing if we find normal chapter
          break
        end
      end
    end
  end

  -- find the last part in the ncx table. it can contain incorrectly nested chapters
  local parts = {}
  for _, navpoint in ipairs(dom:query_selector("navMap navPoint")) do
    -- we are not able to match just direct navPoint ancestors, so we will use this trick
    if navpoint:get_parent():get_element_name() == "navMap" then
      local sec_type, navmark = get_navpoint_info(navpoint)
      if sec_type == "part" then table.insert(parts, navpoint) end
    end
  end
  if #parts > 0 then
    -- fix chapters in the last part
    fix_chapters(parts[#parts])
  end
  return dom
end

function clean_xml_files()
  local opf_file = outputdir .. "/content.opf"
  update_file(opf_file, function(content)
    -- remove wrong elements from the OPF file
    -- open opf file and create LuaXML DOM
    -- the second argument to dom.parse is needed to avoid parsing issues due to the <meta> element.
    local opf_dom = dom.parse(content, {})
    -- remove child elements from elements that don't allow them
    for _, el in ipairs(opf_dom:query_selector("dc|title, dc|creator")) do
      -- get text content
      local text = el:get_text()
      -- replace element text with a new text node containing original text
      el._children = {el:create_text_node(text)}
    end
    return opf_dom:serialize()
  end)
  local ncxfilename = outputdir .. "/" .. outputfilename .. ".ncx"
  update_file(ncxfilename, function(content)
    -- remove spurious spaces at the beginning
    content = content:gsub("^%s*","")
    local ncx_dom = dom.parse(content)
    fix_ncx_toc_levels(ncx_dom)
    -- remove child elements from <text> element
    for _, el in ipairs(ncx_dom:query_selector("text")) do
      local text = el:get_text()
      -- replace element text with a new text node containing original text
      el._children = {el:create_text_node(text)}
    end
    for _, el in ipairs(ncx_dom:query_selector("navPoint")) do
      -- fix attribute names. this issue is caused by a  LuaXML behavior
      -- that makes all attributes lowercase
      el._attr["playOrder"] = el._attr["playorder"]
      el._attr["playorder"] = nil
    end
    return ncx_dom:serialize()
  end)

end

function writeContainer()
  make_opf()
  clean_xml_files()
  pack_container()
end

local function deldir(path)
  for entry in lfs.dir(path) do
    if entry~="." and entry~=".." then  
      os.remove(path.."/"..entry)
    end
  end
  os.remove(path)
  --]]
end

function clean()
  --deldir(outputdir)
  --deldir(metadir)
  --os.remove(mimetype)
end

@claell
Copy link
Author

claell commented Oct 12, 2023

(So I guess my usage of the file was correct, at least for testing purposes. That might be worth mentioning in the docs, as it took me a considerable amount of time to find that out, while it seems to be a good way to quickly test things on Windows with pretty low effort).

zip -v on the command line works for me without problems. That is the weird thing:

zip -v
Copyright (C) 1990-1999 Info-ZIP
Type 'zip "-L"' for software license.
This is Zip 9.5.0 build 3505 (November 29th 1999), by Info-ZIP.
Currently maintained by Onno van der Linden. Please send bug reports to
the authors at [email protected]; see README for details.

Latest sources and executables are at ftp://ftp.cdrom.com/pub/infozip, as of
above date; see http://www.cdrom.com/pub/infozip/Zip.html for other sites.

Compiled with Microsoft C 12.00 (Visual C++ v6.0) for
Windows 9x / Windows NT (32-bit) on Oct 12 2012.

Zip special compilation options:
        ASMV
        USE_EF_UT_TIME
        NTSD_EAS
        [encryption, version 2.9 of 22 April 2000]

Zip environment options:
             ZIP:  [none]
          ZIPOPT:  [none]

Thanks for the code, I'll test that as well.

I just noticed that for my first pasted code, where I didn't execute from within the tex4ebook directory, the error message comes from ...023/texmf-dist/scripts/tex4ebook/tex4ebook-exec_epub.lua, which is the TeX Live path, apparently. Probably, that version is used in case, the directory of the local script isn't found. That explains some things.

I guess, I could change the file as well in that path (now that I found where it is). So that might also be worth to be added to the documentation for Windows :)

@claell
Copy link
Author

claell commented Oct 12, 2023

With your updated code, I don't get the error message, anymore and the conversion still seems to work (as before, but now without an error message):

texlua.exe .\tex4ebook ..\test.tex
[STATUS]  tex4ebook: Conversion started
[STATUS]  tex4ebook: Input file: ..\test.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
        1 Datei(en) kopiert.
Der Befehl "tidy" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
[WARNING] exec_epub: tidy command seems missing, you should install it in order
  to make valid epub file
        1 Datei(en) kopiert.
[STATUS]  tex4ebook: Conversion finished

claell added a commit to claell/tex4ebook that referenced this issue Oct 12, 2023
As discussed in michal-h21#115, some better advice for Windows would have been helpful, so I added it based on my findings.

Also, slight formatting changes (hopefully seen as improvements).
@michal-h21
Copy link
Owner

It is really strange why you got the error in the first place, as it only tried to read the version info from the zip command. I cannot use this fix in the main code, as we need to be able to find if user has zip or miktex-zip.

@claell
Copy link
Author

claell commented Oct 12, 2023

Yes, I completely understand that your posted code cannot be used as fix.

The interesting thing is that with master (current version), the error is displayed, but the EPUB creation doesn't seem to fail (as it was before with the TeX Live 2023 distributed version). So that is already a plus for me, as now things work at least.

It somewhat looks as if lua cannot call zip when it tests for it, but when it actually uses it, then it can call it, because there will be a result. Possibly some permission thing with the specific way that the script tries to test for zip.

@claell
Copy link
Author

claell commented Apr 21, 2024

Just wanted to give an update on this: I recently upgraded TeX Live to 2024 and the issue is still there, for some reason. The good thing is that it doesn't seem to cause any problems, so it is okay.

@michal-h21
Copy link
Owner

So you have to run zip manually?

@claell
Copy link
Author

claell commented Apr 21, 2024

No, it seems to run despite the error note. At least, after running tex4ebook, I get a working .epub file. That's why I said that this is not really a problem.

@michal-h21
Copy link
Owner

Ah, I see. I've just figured that the code for detection of zip was faulty. I didn't realize that the Lua function for command execution always returns an object, even if the command doesn't exists. So it always returned zip as it was the first thing it tested.

@claell
Copy link
Author

claell commented Apr 21, 2024

Not sure whether I get what you are saying here. Are you referring to https://github.com/michal-h21/tex4ebook/blob/master/tex4ebook-exec_epub.lua#L317?

Or maybe https://github.com/michal-h21/tex4ebook/blob/master/tex4ebook-exec_epub.lua#L303?

The return here https://github.com/michal-h21/tex4ebook/blob/master/tex4ebook-exec_epub.lua#L317 actually seems to be the reason why the EPUB can be generated successfully, even if the function thinks that zip was not found on my system.

@michal-h21
Copy link
Owner

It now looks like this:

local function find_zip()
  local zip_handle = assert(io.popen("zip -v 2>&1","r"))
  local miktex_zip = assert(io.popen("miktex-zip -v 2>&1","r"))
  local zip_result = zip_handle:read("*all")
  local miktex_result = miktex_zip:read("*all")
  zip_handle:close()
  miktex_zip:close()
  if zip_result and zip_result:match("Zip") then
    return "zip"
  elseif miktex_result and miktex_result:match("Zip") then
    return "miktex-zip"
  end
  log:warning "It appears you don't have zip command installed. I can't pack the ebook"
  return "zip"
end

So it tries to read from both zip and miktex-zip and detect if the printed command output contains Zip message. If it does, we can assume that the command exists and use it. If bot of these conditios fail, zip is used even though it wasn't detected.

@claell
Copy link
Author

claell commented Apr 21, 2024

Yes. I know. But in my cases that is actually good. Because only the detection doesn't seem to work on my machine. But the command itself exists and can also be used. So I am really happy that this function works that way, as zip can then be successfully called, later (at least, I assume that it is successful, as no further errors seem to occur).

@claell
Copy link
Author

claell commented Apr 21, 2024

Ah, I guess we might have talked about different things. I'll probably wait until the new version is available through TeX Live and then try whether it fixes the detection problem for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants