Commit c87d3e3f authored by Eike Ziller's avatar Eike Ziller

Normalize file paths on OS X

On a case insensitive file system, we want to e.g.
open 'foo.H' when switching between header and source from 'foo.cpp'
if that is how the file appears on the file system.

Since there doesn't seem to be a way to normalize the full path without
resolving symlinks, do it for each path component in turn.

Also add a header for the mac specific utility functions.

Task-number: QTCREATORBUG-13507
Change-Id: I6cf51fed698d12ac56fa1ec051da1b893bb0b065
Reviewed-by: default avatarChristian Stenger <christian.stenger@theqtcompany.com>
Reviewed-by: default avatarMorten Johan Sørvig <morten.sorvig@theqtcompany.com>
Reviewed-by: default avatarEike Ziller <eike.ziller@theqtcompany.com>
parent edfe8371
......@@ -39,11 +39,7 @@
#ifdef Q_OS_OSX
// for file drops from Finder, working around QTBUG-40449
namespace Utils {
namespace Internal {
extern QUrl filePathUrl(const QUrl &url);
} // Internal
} // Utils
#include "fileutils_mac.h"
#endif
namespace Utils {
......
......@@ -49,6 +49,10 @@
#include <shlobj.h>
#endif
#ifdef Q_OS_OSX
#include "fileutils_mac.h"
#endif
QT_BEGIN_NAMESPACE
QDebug operator<<(QDebug dbg, const Utils::FileName &c)
{
......@@ -282,7 +286,7 @@ bool FileUtils::makeWritable(const FileName &path)
return QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser);
}
// makes sure that capitalization of directories is canonical on Windows.
// makes sure that capitalization of directories is canonical on Windows and OS X.
// This mimics the logic in QDeclarative_isFileCaseCorrect
QString FileUtils::normalizePathName(const QString &name)
{
......@@ -297,7 +301,9 @@ QString FileUtils::normalizePathName(const QString &name)
if (!SHGetPathFromIDList(file, buffer))
return name;
return QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer)));
#else // Filesystem is case-insensitive only on Windows
#elif defined(Q_OS_OSX)
return Internal::normalizePathName(name);
#else // do not try to handle case-insensitive file systems on Linux
return name;
#endif
}
......
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef FILEUTILS_MAC_H
#define FILEUTILS_MAC_H
#include <QUrl>
namespace Utils {
namespace Internal {
QUrl filePathUrl(const QUrl &url);
QString normalizePathName(const QString &filePath);
} // Internal
} // Utils
#endif // FILEUTILS_MAC_H
......@@ -28,8 +28,13 @@
**
****************************************************************************/
#include "fileutils_mac.h"
#include "autoreleasepool.h"
#include "qtcassert.h"
#include <QDir>
#include <QFileInfo>
#include <QUrl>
#include <Foundation/NSURL.h>
......@@ -47,5 +52,39 @@ QUrl filePathUrl(const QUrl &url)
return ret;
}
QString normalizePathName(const QString &filePath)
{
AutoreleasePool pool; Q_UNUSED(pool)
// NSURL getResourceValue returns values based on the cleaned path so we need to work on that.
// It also returns the disk name for "/" and "/.." and errors on "" and relative paths,
// so avoid that
// we cannot know the normalized name for relative paths
if (QFileInfo(filePath).isRelative())
return filePath;
QString result;
QString path = QDir::cleanPath(filePath);
// avoid empty paths and paths like "/../foo" or "/.."
if (path.isEmpty() || path.contains(QLatin1String("/../")) || path.endsWith(QLatin1String("/..")))
return filePath;
while (path != QLatin1String("/") /*be defensive->*/&& path != QLatin1String(".") && !path.isEmpty()) {
QFileInfo info(path);
NSURL *nsurl = [NSURL fileURLWithPath:path.toNSString()];
NSString *out;
QString component;
if ([nsurl getResourceValue:(NSString **)&out forKey:NSURLNameKey error:nil])
component = QString::fromNSString(out);
else // e.g. if the full path does not exist
component = info.fileName();
result.prepend(QLatin1Char('/') + component);
path = info.path();
}
QTC_ASSERT(path == QLatin1String("/"), return filePath);
return result;
}
} // Internal
} // Utils
......@@ -206,7 +206,8 @@ FORMS += $$PWD/filewizardpage.ui \
RESOURCES += $$PWD/utils.qrc
osx {
HEADERS += $$PWD/autoreleasepool.h
HEADERS += $$PWD/autoreleasepool.h \
$$PWD/fileutils_mac.h
OBJECTIVE_SOURCES += \
$$PWD/fileutils_mac.mm
LIBS += -framework Foundation
......
......@@ -270,7 +270,7 @@ QtcLibrary {
name: "FileUtils_osx"
condition: qbs.targetOS.contains("osx")
files: [
"fileutils_mac.mm",
"fileutils_mac.h", "fileutils_mac.mm",
]
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment