Customwizards: Add a way of wrapping a Generator script.

Add attribute to XML syntax specifying a script to generate files.
The script must provide a --dry-run mode in which it prints the files
it intends to create and their attributes to stdout.
Rework the CustomWizardContext structure to contain target path
and parameter mappings, simplify some code there.
This commit is contained in:
Friedemann Kleint
2010-09-01 13:27:24 +02:00
parent b719bbda42
commit c6132a05f3
12 changed files with 603 additions and 55 deletions

View File

@@ -32,6 +32,7 @@
#include "customwizardpage.h"
#include "projectexplorer.h"
#include "baseprojectwizarddialog.h"
#include "customwizardscriptgenerator.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
@@ -186,30 +187,80 @@ Core::GeneratedFiles CustomWizard::generateFiles(const QWizard *dialog, QString
// Look for the Custom field page to find the path
const Internal::CustomWizardPage *cwp = findWizardPage<Internal::CustomWizardPage>(dialog);
QTC_ASSERT(cwp, return Core::GeneratedFiles())
QString path = cwp->path();
const FieldReplacementMap fieldMap = replacementMap(dialog);
CustomWizardContextPtr ctx = context();
ctx->targetPath = cwp->path();
ctx->replacements = replacementMap(dialog);
if (CustomWizardPrivate::verbose) {
QString logText;
QTextStream str(&logText);
str << "CustomWizard::generateFiles: " << path << '\n';
const FieldReplacementMap::const_iterator cend = fieldMap.constEnd();
for (FieldReplacementMap::const_iterator it = fieldMap.constBegin(); it != cend; ++it)
str << "CustomWizard::generateFiles: " << ctx->targetPath << '\n';
const FieldReplacementMap::const_iterator cend = context()->replacements.constEnd();
for (FieldReplacementMap::const_iterator it = context()->replacements.constBegin(); it != cend; ++it)
str << " '" << it.key() << "' -> '" << it.value() << "'\n";
qWarning("%s", qPrintable(logText));
}
return generateWizardFiles(path, fieldMap, errorMessage);
return generateWizardFiles(errorMessage);
}
Core::GeneratedFiles CustomWizard::generateWizardFiles(const QString &targetPath,
const FieldReplacementMap &fieldReplacementMap,
QString *errorMessage) const
bool CustomWizard::writeFiles(const Core::GeneratedFiles &files, QString *errorMessage)
{
if (!Core::BaseFileWizard::writeFiles(files, errorMessage))
return false;
if (d->m_parameters->filesGeneratorScript.isEmpty())
return true;
// Prepare run of the custom script to generate. In the case of a
// project wizard that is entirely created by a script,
// the target project directory might not exist.
const CustomWizardContextPtr ctx = context();
QDir targetPathDir(ctx->targetPath);
if (!targetPathDir.exists()) {
if (CustomWizardPrivate::verbose)
qDebug("Creating directory %s", qPrintable(ctx->targetPath));
if (!targetPathDir.mkpath(ctx->targetPath)) {
*errorMessage = QString::fromLatin1("Unable to create the target directory '%1'").arg(ctx->targetPath);
return false;
}
}
// Run the custom script to actually generate the files.
if (!Internal::runCustomWizardGeneratorScript(ctx->targetPath, d->m_parameters->filesGeneratorScriptFullPath(),
ctx->replacements, errorMessage))
return false;
// Paranoia: Check on the files generated by the script:
foreach (const Core::GeneratedFile &generatedFile, files)
if (generatedFile.attributes() & Core::GeneratedFile::CustomGeneratorAttribute)
if (!QFileInfo(generatedFile.path()).isFile()) {
*errorMessage = QString::fromLatin1("%1 failed to generate %2").
arg(d->m_parameters->filesGeneratorScript, generatedFile.path());
return false;
}
return true;
}
Core::GeneratedFiles CustomWizard::generateWizardFiles(QString *errorMessage) const
{
if (CustomWizardPrivate::verbose)
qDebug() << "Replacements" << fieldReplacementMap;
// Create files
Core::GeneratedFiles rc;
const CustomWizardContextPtr ctx = context();
QTC_ASSERT(!ctx->targetPath.isEmpty(), return rc)
if (CustomWizardPrivate::verbose)
qDebug() << "CustomWizard::generateWizardFiles: in "
<< ctx->targetPath << ", using: " << ctx->replacements;
// If generator script is non-empty, do a dry run to get it's files.
if (!d->m_parameters->filesGeneratorScript.isEmpty()) {
rc += Internal::dryRunCustomWizardGeneratorScript(ctx->targetPath,
d->m_parameters->filesGeneratorScriptFullPath(),
ctx->replacements, errorMessage);
if (rc.isEmpty())
return rc;
}
// Add the template files specified by the <file> elements.
foreach(const Internal::CustomWizardFile &file, d->m_parameters->files)
if (!createFile(file, d->m_parameters->directory, targetPath, fieldReplacementMap, &rc, errorMessage))
if (!createFile(file, d->m_parameters->directory, ctx->targetPath, context()->replacements, &rc, errorMessage))
return Core::GeneratedFiles();
return rc;
}
@@ -437,13 +488,22 @@ Core::GeneratedFiles CustomProjectWizard::generateFiles(const QWizard *w, QStrin
{
const BaseProjectWizardDialog *dialog = qobject_cast<const BaseProjectWizardDialog *>(w);
QTC_ASSERT(dialog, return Core::GeneratedFiles())
const QString targetPath = dialog->path() + QLatin1Char('/') + dialog->projectName();
// Add project name as macro.
// Add project name as macro. Path is here under project directory
CustomWizardContextPtr ctx = context();
ctx->targetPath = dialog->path() + QLatin1Char('/') + dialog->projectName();
FieldReplacementMap fieldReplacementMap = replacementMap(dialog);
fieldReplacementMap.insert(QLatin1String("ProjectName"), dialog->projectName());
ctx->replacements = fieldReplacementMap;
if (CustomWizardPrivate::verbose)
qDebug() << "CustomProjectWizard::generateFiles" << dialog << targetPath << fieldReplacementMap;
return generateWizardFiles(targetPath, fieldReplacementMap, errorMessage);
qDebug() << "CustomProjectWizard::generateFiles" << dialog << ctx->targetPath << ctx->replacements;
const Core::GeneratedFiles generatedFiles = generateWizardFiles(errorMessage);
// Find the project file and store in context
foreach(const Core::GeneratedFile &f, generatedFiles)
if (f.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
ctx->projectFilePath = f.path();
break;
}
return generatedFiles;
}
bool CustomProjectWizard::postGenerateOpen(const Core::GeneratedFiles &l, QString *errorMessage)
@@ -461,23 +521,11 @@ bool CustomProjectWizard::postGenerateOpen(const Core::GeneratedFiles &l, QStrin
return BaseFileWizard::postGenerateOpenEditors(l, errorMessage);
}
QString CustomProjectWizard::generatedProjectFilePath(const QWizard *wizard) const
QString CustomProjectWizard::generatedProjectFilePath(const QWizard *) const
{
const BaseProjectWizardDialog *dialog = qobject_cast<const BaseProjectWizardDialog *>(wizard);
QTC_ASSERT(dialog, return QString())
const QString targetPath = dialog->path() + QLatin1Char('/') + dialog->projectName();
const QChar slash = QLatin1Char('/');
// take the first from parameters()->files list which have cwFile.openProject set
foreach(const Internal::CustomWizardFile &file, parameters()->files) {
if (file.openProject) {
FieldReplacementMap fieldReplacementMap = replacementMap(dialog);
fieldReplacementMap.insert(QLatin1String("ProjectName"), dialog->projectName());
QString target = file.target;
Internal::CustomWizardContext::replaceFields(fieldReplacementMap, &target);
return QDir::toNativeSeparators(targetPath + slash + target);
}
}
return QString();
if (CustomWizardPrivate::verbose)
qDebug("CustomProjectWizard::generatedProjectFilePath: '%s'", qPrintable(context()->projectFilePath));
return context()->projectFilePath;
}
bool CustomProjectWizard::postGenerateFiles(const QWizard *, const Core::GeneratedFiles &l, QString *errorMessage)