Add -copyfiles command line option to tex2lyx

If this option is given, included files will be copied to the output directory.
Also -roundtrip is now allowed with given output file.
-copyfiles is useful if you want to ensure that no file (not even an included
one) is overwritten by a subsequent export from LyX. Both changes are needed
for unit tests that do not write to the source directory.
This commit is contained in:
Georg Baum 2012-10-03 13:23:27 +02:00
parent 02c73cd721
commit 24181cf28e
4 changed files with 212 additions and 64 deletions

View File

@ -21,7 +21,7 @@ options.
.PP
\fBtex2lyx\fR [ \fB\-userdir\fR \fIuserdir\fR ] [ \fB\-systemdir\fR \fIsystemdir\fR ]
[ \fB\-n\fR ] [ \fB\-c\fR \fItextclass\fR ] [\ \fB\-s\fR\ \fIsfile1\fR[,\fIsfile2\fR...]] [
\fB\-roundtrip\fR ] \fIinputfile\fR [ \fIoutputfile\fR ]
\fB\-roundtrip\fR ] [ \fB\-copyfiles\fR ] \fIinputfile\fR [ \fIoutputfile\fR ]
.\" .PP
.\" \fBtex2lyx\fR [ \fB\-userdir\fR \fIuserdir\fR ] [ \fB\-systemdir\fR \fIsystemdir\fR ]
.\" [\ \fB\-r\fR\ \fIrenv1\fR[,\fIrenv2\fR...]] [\ \fB\-s\fR\ \fIsfile1\fR[,\fIsfile2\fR...]]
@ -70,12 +70,21 @@ Specify a user directory. Normally, you shouldn't need this. Your LyX user direc
chosen. Cf. the section \f(CWFILES\fR for details.
.TP
.BI \-roundtrip
Call LyX to re-export the created output file to LaTeX. The output file name
is always determined automatically to avoid over-writing the input file by
accident: If the input file is named \fIfoo.tex\fR the output file will be
Call LyX to re-export the created output file to LaTeX. If the output file name
is not given it is determined automatically to avoid over-writing the input file
by accident: If the input file is named \fIfoo.tex\fR the output file will be
named \fIfoo.lyx.lyx\fR, and the re-exported file will be named
\fIfoo.lyx.tex\fR.
.TP
.BI \-copyfiles
Copy all included files below the input directory and that \fBtex2lyx\fR is
aware of to the output directory if the output file is located in a different
directory than the input file. This is useful if you want to ensure that no
included file is overwritten (either in roundtrip mode or by a later export
from LyX). Please note that the resulting document may be uncompilable. This
happens if it needs files that \fBtex2lyx\fR does not know about and therefore
does not copy to the output directory.
.TP
.BI \-help
Help. Print out usage information and quit.
.TP

View File

@ -446,6 +446,7 @@ void read_syntaxfile(FileName const & file_name)
string documentclass;
string default_encoding;
string syntaxfile;
bool copy_files = false;
bool overwrite_files = false;
int error_code = 0;
@ -458,6 +459,7 @@ int parse_help(string const &, string const &)
cerr << "Usage: tex2lyx [options] infile.tex [outfile.lyx]\n"
"Options:\n"
"\t-c textclass Declare the textclass.\n"
"\t-copyfiles Copy all included files to the directory of outfile.lyx.\n"
"\t-e encoding Set the default encoding (latex name).\n"
"\t-f Force overwrite of .lyx files.\n"
"\t-help Print this message and quit.\n"
@ -571,6 +573,13 @@ int parse_roundtrip(string const &, string const &)
}
int parse_copyfiles(string const &, string const &)
{
copy_files = true;
return 0;
}
void easyParse(int & argc, char * argv[])
{
map<string, cmd_helper> cmdmap;
@ -589,6 +598,7 @@ void easyParse(int & argc, char * argv[])
cmdmap["-sysdir"] = parse_sysdir;
cmdmap["-userdir"] = parse_userdir;
cmdmap["-roundtrip"] = parse_roundtrip;
cmdmap["-copyfiles"] = parse_copyfiles;
for (int i = 1; i < argc; ++i) {
map<string, cmd_helper>::const_iterator it
@ -619,21 +629,42 @@ void easyParse(int & argc, char * argv[])
// path of the first parsed file
string masterFilePath;
string masterFilePathLyX;
string masterFilePathTeX;
// path of the currently parsed file
string parentFilePath;
string parentFilePathTeX;
} // anonymous namespace
string getMasterFilePath()
string getMasterFilePath(bool input)
{
return masterFilePath;
return input ? masterFilePathTeX : masterFilePathLyX;
}
string getParentFilePath()
string getParentFilePath(bool input)
{
return parentFilePath;
if (input)
return parentFilePathTeX;
string const rel = to_utf8(makeRelPath(from_utf8(masterFilePathTeX),
from_utf8(parentFilePathTeX)));
if (rel.substr(0, 3) == "../") {
// The parent is not below the master - keep the path
return parentFilePathTeX;
}
return makeAbsPath(rel, masterFilePathLyX).absFileName();
}
bool copyFiles()
{
return copy_files;
}
bool overwriteFiles()
{
return overwrite_files;
}
@ -645,7 +676,7 @@ namespace {
* be used more than once for included documents.
* Caution: Overwrites the existing preamble settings if the new document
* contains a preamble.
* You must ensure that \p parentFilePath is properly set before calling
* You must ensure that \p parentFilePathTeX is properly set before calling
* this function!
*/
bool tex2lyx(idocstream & is, ostream & os, string encoding)
@ -720,10 +751,10 @@ bool tex2lyx(FileName const & infilename, ostream & os, string const & encoding)
<< "\" for reading." << endl;
return false;
}
string const oldParentFilePath = parentFilePath;
parentFilePath = onlyPath(infilename.absFileName());
string const oldParentFilePath = parentFilePathTeX;
parentFilePathTeX = onlyPath(infilename.absFileName());
bool retval = tex2lyx(is, os, encoding);
parentFilePath = oldParentFilePath;
parentFilePathTeX = oldParentFilePath;
return retval;
}
@ -826,20 +857,28 @@ int main(int argc, char * argv[])
infilename = makeAbsPath(infilename).absFileName();
string outfilename;
if (roundtrip) {
if (argc > 2) {
// Do not allow a user supplied output filename
// (otherwise it could easily happen that LyX would
// overwrite the original .tex file)
cerr << "Error: output filename must not be given in roundtrip mode."
<< endl;
return EXIT_FAILURE;
}
outfilename = changeExtension(infilename, ".lyx.lyx");
} else if (argc > 2) {
outfilename = internal_path(os::utf8_argv(2));
if (outfilename != "-")
outfilename = makeAbsPath(outfilename).absFileName();
if (roundtrip) {
if (outfilename == "-") {
cerr << "Error: Writing to standard output is "
"not supported in roundtrip mode."
<< endl;
return EXIT_FAILURE;
}
string texfilename = changeExtension(outfilename, ".tex");
if (equivalent(FileName(infilename), FileName(texfilename))) {
cerr << "Error: The input file `" << infilename
<< "´ would be overwritten by the TeX file exported from `"
<< outfilename << "´ in roundtrip mode." << endl;
return EXIT_FAILURE;
}
}
} else if (roundtrip) {
// avoid overwriting the input file
outfilename = changeExtension(infilename, ".lyx.lyx");
} else
outfilename = changeExtension(infilename, ".lyx");
@ -876,18 +915,23 @@ int main(int argc, char * argv[])
theModuleList.read();
// The real work now.
masterFilePath = onlyPath(infilename);
parentFilePath = masterFilePath;
masterFilePathTeX = onlyPath(infilename);
parentFilePathTeX = masterFilePathTeX;
if (outfilename == "-") {
// assume same directory as input file
masterFilePathLyX = masterFilePathTeX;
if (tex2lyx(FileName(infilename), cout, default_encoding))
return EXIT_SUCCESS;
} else if (roundtrip) {
} else {
masterFilePathLyX = onlyPath(outfilename);
if (roundtrip) {
if (tex2tex(infilename, FileName(outfilename), default_encoding))
return EXIT_SUCCESS;
} else {
if (tex2lyx(infilename, FileName(outfilename), default_encoding))
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}

View File

@ -173,10 +173,14 @@ extern bool is_nonCJKJapanese;
/// LyX format that is created by tex2lyx
extern int const LYX_FORMAT;
/// path of the master .tex file
extern std::string getMasterFilePath();
/// path of the currently processed .tex file
extern std::string getParentFilePath();
/// Absolute path of the master .lyx or .tex file
extern std::string getMasterFilePath(bool input);
/// Absolute path of the currently processed .lyx or .tex file
extern std::string getParentFilePath(bool input);
/// Is it allowed to overwrite existing files?
extern bool overwriteFiles();
/// Do we need to copy included files to the output directory?
extern bool copyFiles();
/*!

View File

@ -1834,15 +1834,88 @@ string const normalize_filename(string const & name)
/// Convert \p name from TeX convention (relative to master file) to LyX
/// convention (relative to .lyx file) if it is relative
void fix_relative_filename(string & name)
void fix_child_filename(string & name)
{
if (FileName::isAbsolute(name))
return;
string const absMasterTeX = getMasterFilePath(true);
bool const isabs = FileName::isAbsolute(name);
// convert from "relative to .tex master" to absolute original path
if (!isabs)
name = makeAbsPath(name, absMasterTeX).absFileName();
bool copyfile = copyFiles();
// convert from absolute original path to "relative to master file"
string const rel = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absMasterTeX)));
// Do not copy if the file is not in or below the directory of the
// master, since in this case the new path might be impossible to
// create. Example:
// absMasterTeX = "/foo/bar/"
// absMasterLyX = "/bar/"
// name = "/baz.eps" => new absolute name would be "/../baz.eps"
if (copyfile && rel.substr(0, 3) == "../")
copyfile = false;
string const absParentLyX = getParentFilePath(false);
if (copyfile) {
// re-interpret "relative to .tex file" as "relative to .lyx file"
// (is different if the master .lyx file resides in a
// different path than the master .tex file)
string const absMasterLyX = getMasterFilePath(false);
name = makeAbsPath(rel, absMasterLyX).absFileName();
if (!isabs) {
// convert from absolute original path to
// "relative to .lyx file"
name = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absParentLyX)));
}
}
else if (!isabs) {
// convert from absolute original path to "relative to .lyx file"
name = to_utf8(makeRelPath(from_utf8(name),
from_utf8(absParentLyX)));
}
}
string const absMaster = makeAbsPath(getMasterFilePath()).absFileName();
string const absParent = makeAbsPath(getParentFilePath()).absFileName();
string const abs = makeAbsPath(name, absMaster).absFileName();
name = to_utf8(makeRelPath(from_utf8(abs), from_utf8(absParent)));
void copy_file(FileName const & src, string dstname)
{
if (!copyFiles())
return;
string const absParent = getParentFilePath(false);
FileName dst;
if (FileName::isAbsolute(dstname))
dst = FileName(dstname);
else
dst = makeAbsPath(dstname, absParent);
string const absMaster = getMasterFilePath(false);
string const rel = to_utf8(makeRelPath(from_utf8(dst.absFileName()),
from_utf8(absMaster)));
// Do not copy if the file is not in or below the directory of the
// master (see above)
if (rel.substr(0, 3) == "../")
return;
FileName const srcpath = src.onlyPath();
FileName const dstpath = dst.onlyPath();
if (equivalent(srcpath, dstpath))
return;
if (!dstpath.isDirectory()) {
if (!dstpath.createPath()) {
cerr << "Warning: Could not create directory for file `"
<< dst.absFileName() << "´." << endl;
return;
}
}
if (dst.isReadableFile()) {
if (overwriteFiles())
cerr << "Warning: Overwriting existing file `"
<< dst.absFileName() << "´." << endl;
else {
cerr << "Warning: Not overwriting existing file `"
<< dst.absFileName() << "´." << endl;
return;
}
}
if (!src.copyTo(dst))
cerr << "Warning: Could not copy file `" << src.absFileName()
<< "´ to `" << dst.absFileName() << "´." << endl;
}
@ -2533,7 +2606,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
skip_braces(p);
p.get_token();
string name = normalize_filename(p.verbatim_item());
string const path = makeAbsPath(getMasterFilePath()).absFileName();
string const path = getMasterFilePath(true);
// We want to preserve relative / absolute filenames,
// therefore path is only used for testing
// The file extension is in every case ".tex".
@ -2548,9 +2621,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
if (!Gnumeric_name.empty())
name = Gnumeric_name;
}
if (makeAbsPath(name, path).exists())
fix_relative_filename(name);
else
FileName const absname = makeAbsPath(name, path);
if (absname.exists()) {
fix_child_filename(name);
copy_file(absname, name);
} else
cerr << "Warning: Could not find file '"
<< name << "'." << endl;
context.check_layout(os);
@ -2560,7 +2635,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
end_inset(os);
context.check_layout(os);
macro = false;
// register the packages that are automatically reloaded
// register the packages that are automatically loaded
// by the Gnumeric template
registerExternalTemplatePackages("GnumericSpreadsheet");
}
@ -2760,7 +2835,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
opts["clip"] = string();
string name = normalize_filename(p.verbatim_item());
string const path = makeAbsPath(getMasterFilePath()).absFileName();
string const path = getMasterFilePath(true);
// We want to preserve relative / absolute filenames,
// therefore path is only used for testing
if (!makeAbsPath(name, path).exists()) {
@ -2795,9 +2870,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
}
}
if (makeAbsPath(name, path).exists())
fix_relative_filename(name);
else
FileName const absname = makeAbsPath(name, path);
if (absname.exists()) {
fix_child_filename(name);
copy_file(absname, name);
} else
cerr << "Warning: Could not find graphics file '"
<< name << "'." << endl;
@ -3725,7 +3802,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
name += p.get_token().asInput();
context.check_layout(os);
string filename(normalize_filename(p.getArg('{', '}')));
string const path = makeAbsPath(getMasterFilePath()).absFileName();
string const path = getMasterFilePath(true);
// We want to preserve relative / absolute filenames,
// therefore path is only used for testing
if ((t.cs() == "include" || t.cs() == "input") &&
@ -3743,13 +3820,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
if (makeAbsPath(filename, path).exists()) {
string const abstexname =
makeAbsPath(filename, path).absFileName();
string const abslyxname =
changeExtension(abstexname, ".lyx");
string const absfigname =
changeExtension(abstexname, ".fig");
fix_relative_filename(filename);
fix_child_filename(filename);
string const lyxname =
changeExtension(filename, ".lyx");
string const abslyxname = makeAbsPath(
lyxname, getParentFilePath(false)).absFileName();
bool xfig = false;
external = FileName(absfigname).exists();
if (t.cs() == "input") {
@ -3795,16 +3872,24 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
}
if (external) {
outname = changeExtension(filename, ".fig");
FileName abssrc(changeExtension(abstexname, ".fig"));
copy_file(abssrc, outname);
} else if (xfig) {
// Don't try to convert, the result
// would be full of ERT.
outname = filename;
FileName abssrc(abstexname);
copy_file(abssrc, outname);
} else if (t.cs() != "verbatiminput" &&
tex2lyx(abstexname, FileName(abslyxname),
p.getEncoding())) {
outname = lyxname;
// no need to call copy_file
// tex2lyx creates the file
} else {
outname = filename;
FileName abssrc(abstexname);
copy_file(abssrc, outname);
}
} else {
cerr << "Warning: Could not find included file '"
@ -4185,7 +4270,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
vector<string> keys;
split_map(arg, opts, keys);
string name = normalize_filename(p.verbatim_item());
string const path = makeAbsPath(getMasterFilePath()).absFileName();
string const path = getMasterFilePath(true);
// We want to preserve relative / absolute filenames,
// therefore path is only used for testing
if (!makeAbsPath(name, path).exists()) {
@ -4199,9 +4284,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
pdflatex = true;
}
}
if (makeAbsPath(name, path).exists())
fix_relative_filename(name);
else
FileName const absname = makeAbsPath(name, path);
if (absname.exists())
{
fix_child_filename(name);
copy_file(absname, name);
} else
cerr << "Warning: Could not find file '"
<< name << "'." << endl;
// write output
@ -4250,7 +4338,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
else if (t.cs() == "loadgame") {
p.skip_spaces();
string name = normalize_filename(p.verbatim_item());
string const path = makeAbsPath(getMasterFilePath()).absFileName();
string const path = getMasterFilePath(true);
// We want to preserve relative / absolute filenames,
// therefore path is only used for testing
if (!makeAbsPath(name, path).exists()) {
@ -4262,9 +4350,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
if (!lyxskak_name.empty())
name = lyxskak_name;
}
if (makeAbsPath(name, path).exists())
fix_relative_filename(name);
else
FileName const absname = makeAbsPath(name, path);
if (absname.exists())
{
fix_child_filename(name);
copy_file(absname, name);
} else
cerr << "Warning: Could not find file '"
<< name << "'." << endl;
context.check_layout(os);