Python: Use FilePath for absolute paths to project files

Change-Id: Ied4db237fe6a3b9532fced7c575a8a3717b405fc
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
David Schulz
2023-06-06 12:53:58 +02:00
parent d548c973cf
commit 45acf2d49e

View File

@@ -51,11 +51,8 @@ public:
const FilePath &newFilePath) override; const FilePath &newFilePath) override;
QString name() const override { return QLatin1String("python"); } QString name() const override { return QLatin1String("python"); }
bool saveRawFileList(const QStringList &rawFileList);
bool saveRawList(const QStringList &rawList, const FilePath &filePath);
void parse(); void parse();
QStringList processEntries(const QStringList &paths, bool save();
QHash<QString, QString> *map = nullptr) const;
bool writePyProjectFile(const FilePath &filePath, QString &content, bool writePyProjectFile(const FilePath &filePath, QString &content,
const QStringList &rawList, QString *errorMessage); const QStringList &rawList, QString *errorMessage);
@@ -63,12 +60,14 @@ public:
void triggerParsing() final; void triggerParsing() final;
private: private:
QStringList m_rawFileList; struct FileEntry {
QStringList m_files; QString rawEntry;
QStringList m_rawQmlImportPathList; FilePath filePath;
QStringList m_qmlImportPaths; };
QHash<QString, QString> m_rawListEntries; QList<FileEntry> processEntries(const QStringList &paths) const;
QHash<QString, QString> m_rawQmlImportPathEntries;
QList<FileEntry> m_files;
QList<FileEntry> m_qmlImportPaths;
}; };
/** /**
@@ -226,20 +225,19 @@ void PythonBuildSystem::triggerParsing()
QList<BuildTargetInfo> appTargets; QList<BuildTargetInfo> appTargets;
auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory()); auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory());
for (const QString &f : std::as_const(m_files)) { for (const FileEntry &entry: std::as_const(m_files)) {
const QString displayName = baseDir.relativeFilePath(f); const QString displayName = entry.filePath.relativePathFrom(projectDirectory()).toUserOutput();
const FilePath filePath = FilePath::fromString(f); const FileType fileType = getFileType(entry.filePath);
const FileType fileType = getFileType(filePath);
newRoot->addNestedNode(std::make_unique<PythonFileNode>(filePath, displayName, fileType)); newRoot->addNestedNode(std::make_unique<PythonFileNode>(entry.filePath, displayName, fileType));
const MimeType mt = mimeTypeForFile(filePath, MimeMatchMode::MatchExtension); const MimeType mt = mimeTypeForFile(entry.filePath, MimeMatchMode::MatchExtension);
if (mt.matchesName(Constants::C_PY_MIMETYPE) || mt.matchesName(Constants::C_PY3_MIMETYPE)) { if (mt.matchesName(Constants::C_PY_MIMETYPE) || mt.matchesName(Constants::C_PY3_MIMETYPE)) {
BuildTargetInfo bti; BuildTargetInfo bti;
bti.displayName = displayName; bti.displayName = displayName;
bti.buildKey = f; bti.buildKey = entry.filePath.toString();
bti.targetFilePath = filePath; bti.targetFilePath = entry.filePath;
bti.projectFilePath = projectFilePath(); bti.projectFilePath = projectFilePath();
bti.isQtcRunnable = filePath.fileName() == "main.py"; bti.isQtcRunnable = entry.filePath.fileName() == "main.py";
appTargets.append(bti); appTargets.append(bti);
} }
} }
@@ -252,9 +250,9 @@ void PythonBuildSystem::triggerParsing()
const auto hiddenRccFolders = project()->files(Project::HiddenRccFolders); const auto hiddenRccFolders = project()->files(Project::HiddenRccFolders);
auto projectInfo = modelManager->defaultProjectInfoForProject(project(), hiddenRccFolders); auto projectInfo = modelManager->defaultProjectInfoForProject(project(), hiddenRccFolders);
for (const QString &importPath : std::as_const(m_qmlImportPaths)) { for (const FileEntry &importPath : std::as_const(m_qmlImportPaths)) {
const FilePath filePath = FilePath::fromString(importPath); if (!importPath.filePath.isEmpty())
projectInfo.importPaths.maybeInsert(filePath, QmlJS::Dialect::Qml); projectInfo.importPaths.maybeInsert(importPath.filePath, QmlJS::Dialect::Qml);
} }
modelManager->updateProjectInfo(projectInfo, project()); modelManager->updateProjectInfo(projectInfo, project());
@@ -265,15 +263,10 @@ void PythonBuildSystem::triggerParsing()
emitBuildSystemUpdated(); emitBuildSystemUpdated();
} }
bool PythonBuildSystem::saveRawFileList(const QStringList &rawFileList) bool PythonBuildSystem::save()
{
const bool result = saveRawList(rawFileList, projectFilePath());
// refresh(PythonProject::Files);
return result;
}
bool PythonBuildSystem::saveRawList(const QStringList &rawList, const FilePath &filePath)
{ {
const FilePath filePath = projectFilePath();
const QStringList rawList = Utils::transform(m_files, &FileEntry::rawEntry);
const FileChangeBlocker changeGuarg(filePath); const FileChangeBlocker changeGuarg(filePath);
bool result = false; bool result = false;
@@ -332,28 +325,26 @@ bool PythonBuildSystem::writePyProjectFile(const FilePath &filePath, QString &co
bool PythonBuildSystem::addFiles(Node *, const FilePaths &filePaths, FilePaths *) bool PythonBuildSystem::addFiles(Node *, const FilePaths &filePaths, FilePaths *)
{ {
QStringList newList = m_rawFileList; const Utils::FilePath projectDir = projectDirectory();
const QDir baseDir(projectDirectory().toString()); for (const FilePath &filePath : filePaths) {
for (const FilePath &filePath : filePaths) if (!projectDir.isSameDevice(filePath))
newList.append(baseDir.relativeFilePath(filePath.toString())); return false;
m_files.append(FileEntry{filePath.relativePathFrom(projectDir).toString(), filePath});
}
return saveRawFileList(newList); return save();
} }
RemovedFilesFromProject PythonBuildSystem::removeFiles(Node *, const FilePaths &filePaths, FilePaths *) RemovedFilesFromProject PythonBuildSystem::removeFiles(Node *, const FilePaths &filePaths, FilePaths *)
{ {
QStringList newList = m_rawFileList;
for (const FilePath &filePath : filePaths) { for (const FilePath &filePath : filePaths) {
const QHash<QString, QString>::iterator i = m_rawListEntries.find(filePath.toString()); Utils::eraseOne(m_files,
if (i != m_rawListEntries.end()) [filePath](const FileEntry &entry) { return filePath == entry.filePath; });
newList.removeOne(i.value());
} }
bool res = saveRawFileList(newList); return save() ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error;
return res ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error;
} }
bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &) bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &)
@@ -363,45 +354,45 @@ bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &)
bool PythonBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath) bool PythonBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
{ {
QStringList newList = m_rawFileList; for (FileEntry &entry : m_files) {
if (entry.filePath == oldFilePath) {
const QHash<QString, QString>::iterator i = m_rawListEntries.find(oldFilePath.toString()); entry.filePath = newFilePath;
if (i != m_rawListEntries.end()) { entry.rawEntry = newFilePath.relativeChildPath(projectDirectory()).toString();
const int index = newList.indexOf(i.value()); break;
if (index != -1) {
const QDir baseDir(projectDirectory().toString());
newList.replace(index, baseDir.relativeFilePath(newFilePath.toString()));
} }
} }
return saveRawFileList(newList); return save();
} }
void PythonBuildSystem::parse() void PythonBuildSystem::parse()
{ {
m_rawListEntries.clear(); m_files.clear();
m_rawQmlImportPathEntries.clear(); m_qmlImportPaths.clear();
QStringList files;
QStringList qmlImportPaths;
const FilePath filePath = projectFilePath(); const FilePath filePath = projectFilePath();
// The PySide project file is JSON based // The PySide project file is JSON based
if (filePath.endsWith(".pyproject")) { if (filePath.endsWith(".pyproject")) {
QString errorMessage; QString errorMessage;
m_rawFileList = readLinesJson(filePath, &errorMessage); files = readLinesJson(filePath, &errorMessage);
if (!errorMessage.isEmpty()) if (!errorMessage.isEmpty())
MessageManager::writeFlashing(errorMessage); MessageManager::writeFlashing(errorMessage);
errorMessage.clear(); errorMessage.clear();
m_rawQmlImportPathList = readImportPathsJson(filePath, &errorMessage); qmlImportPaths = readImportPathsJson(filePath, &errorMessage);
if (!errorMessage.isEmpty()) if (!errorMessage.isEmpty())
MessageManager::writeFlashing(errorMessage); MessageManager::writeFlashing(errorMessage);
} else if (filePath.endsWith(".pyqtc")) { } else if (filePath.endsWith(".pyqtc")) {
// To keep compatibility with PyQt we keep the compatibility with plain // To keep compatibility with PyQt we keep the compatibility with plain
// text files as project files. // text files as project files.
m_rawFileList = readLines(filePath); files = readLines(filePath);
} }
m_files = processEntries(m_rawFileList, &m_rawListEntries); m_files = processEntries(files);
m_qmlImportPaths = processEntries(m_rawQmlImportPathList, &m_rawQmlImportPathEntries); m_qmlImportPaths = processEntries(qmlImportPaths);
} }
/** /**
@@ -426,38 +417,25 @@ static void expandEnvironmentVariables(const Environment &env, QString &string)
/** /**
* Expands environment variables and converts the path from relative to the * Expands environment variables and converts the path from relative to the
* project to an absolute path. * project to an absolute path for all given raw paths
*
* The \a map variable is an optional argument that will map the returned
* absolute paths back to their original \a paths.
*/ */
QStringList PythonBuildSystem::processEntries(const QStringList &paths, QList<PythonBuildSystem::FileEntry> PythonBuildSystem::processEntries(
QHash<QString, QString> *map) const const QStringList &rawPaths) const
{ {
QList<FileEntry> processed;
const FilePath projectDir = projectDirectory();
const Environment env = projectDirectory().deviceEnvironment(); const Environment env = projectDirectory().deviceEnvironment();
const QDir projectDir(projectDirectory().toString());
QFileInfo fileInfo; for (const QString &rawPath : rawPaths) {
QStringList absolutePaths; FilePath resolvedPath;
for (const QString &path : paths) { QString path = rawPath.trimmed();
QString trimmedPath = path.trimmed(); if (!path.isEmpty()) {
if (trimmedPath.isEmpty()) expandEnvironmentVariables(env, path);
continue; resolvedPath = projectDir.resolvePath(path);
expandEnvironmentVariables(env, trimmedPath);
trimmedPath = FilePath::fromUserInput(trimmedPath).toString();
fileInfo.setFile(projectDir, trimmedPath);
if (fileInfo.exists()) {
const QString absPath = fileInfo.absoluteFilePath();
absolutePaths.append(absPath);
if (map)
map->insert(absPath, trimmedPath);
} }
processed << FileEntry{rawPath, resolvedPath};
} }
absolutePaths.removeDuplicates(); return processed;
return absolutePaths;
} }
Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *errorMessage) Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *errorMessage)