forked from qt-creator/qt-creator
Utils: Add std::expected implementation
Adds a std::expected implementation that is compatible with >= C++11. FilePath::fileContents and FilePath::writeFileContents as well as FilePath::copyFile are changed to return std::expected. A couple of macros have been added to aid in using the expected types. An auto test was added showing how to use the library. Change-Id: Ibe3aecfc1029a0cf13b45bf5184ff03a04a2393b Reviewed-by: Eike Ziller <eike.ziller@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
12
README.md
12
README.md
@@ -688,3 +688,15 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
### TartanLlama/expected
|
||||||
|
|
||||||
|
Implementation of std::expected compatible with C++11/C++14/C++17.
|
||||||
|
|
||||||
|
https://github.com/TartanLlama/expected
|
||||||
|
|
||||||
|
To the extent possible under law, the author(s) have dedicated all
|
||||||
|
copyright and related and neighboring rights to this software to the
|
||||||
|
public domain worldwide. This software is distributed without any warranty.
|
||||||
|
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
@@ -988,5 +988,19 @@
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
\li \b TartanLlama/expected
|
||||||
|
|
||||||
|
Implementation of std::expected compatible with C++11/C++14/C++17.
|
||||||
|
|
||||||
|
The sources can be found in:
|
||||||
|
\list
|
||||||
|
\li \c QtCreator/src/libs/3rdparty/tl_expected
|
||||||
|
\li \l https://github.com/TartanLlama/expected
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||||
|
|
||||||
|
https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
\endlist
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
121
src/libs/3rdparty/tl_expected/COPYING
vendored
Normal file
121
src/libs/3rdparty/tl_expected/COPYING
vendored
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||||
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||||
|
HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
|
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||||
|
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
|
authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for
|
||||||
|
the purpose of contributing to a commons of creative, cultural and
|
||||||
|
scientific works ("Commons") that the public can reliably and without fear
|
||||||
|
of later claims of infringement build upon, modify, incorporate in other
|
||||||
|
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||||
|
and for any purposes, including without limitation commercial purposes.
|
||||||
|
These owners may contribute to the Commons to promote the ideal of a free
|
||||||
|
culture and the further production of creative, cultural and scientific
|
||||||
|
works, or to gain reputation or greater distribution for their Work in
|
||||||
|
part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any
|
||||||
|
expectation of additional consideration or compensation, the person
|
||||||
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||||
|
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||||
|
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||||
|
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||||
|
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
|
Related Rights"). Copyright and Related Rights include, but are not
|
||||||
|
limited to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display,
|
||||||
|
communicate, and translate a Work;
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or
|
||||||
|
likeness depicted in a Work;
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
|
subject to the limitations in paragraph 4(a), below;
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
|
in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation
|
||||||
|
thereof, including any amended or successor version of such
|
||||||
|
directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the
|
||||||
|
world based on applicable law or treaty, and any national
|
||||||
|
implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||||
|
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||||
|
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||||
|
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||||
|
of action, whether now known or unknown (including existing as well as
|
||||||
|
future claims and causes of action), in the Work (i) in all territories
|
||||||
|
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||||
|
treaty (including future time extensions), (iii) in any current or future
|
||||||
|
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional
|
||||||
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||||
|
member of the public at large and to the detriment of Affirmer's heirs and
|
||||||
|
successors, fully intending that such Waiver shall not be subject to
|
||||||
|
revocation, rescission, cancellation, termination, or any other legal or
|
||||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||||
|
be judged legally invalid or ineffective under applicable law, then the
|
||||||
|
Waiver shall be preserved to the maximum extent permitted taking into
|
||||||
|
account Affirmer's express Statement of Purpose. In addition, to the
|
||||||
|
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||||
|
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||||
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||||
|
maximum duration provided by applicable law or treaty (including future
|
||||||
|
time extensions), (iii) in any current or future medium and for any number
|
||||||
|
of copies, and (iv) for any purpose whatsoever, including without
|
||||||
|
limitation commercial, advertising or promotional purposes (the
|
||||||
|
"License"). The License shall be deemed effective as of the date CC0 was
|
||||||
|
applied by Affirmer to the Work. Should any part of the License for any
|
||||||
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||||
|
of the License, and in such case Affirmer hereby affirms that he or she
|
||||||
|
will not (i) exercise any of his or her remaining Copyright and Related
|
||||||
|
Rights in the Work or (ii) assert any associated claims and causes of
|
||||||
|
action with respect to the Work, in either case contrary to Affirmer's
|
||||||
|
express Statement of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
|
surrendered, licensed or otherwise affected by this document.
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or
|
||||||
|
warranties of any kind concerning the Work, express, implied,
|
||||||
|
statutory or otherwise, including without limitation warranties of
|
||||||
|
title, merchantability, fitness for a particular purpose, non
|
||||||
|
infringement, or the absence of latent or other defects, accuracy, or
|
||||||
|
the present or absence of errors, whether or not discoverable, all to
|
||||||
|
the greatest extent permissible under applicable law.
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without
|
||||||
|
limitation any person's Copyright and Related Rights in the Work.
|
||||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||||
|
consents, permissions or other rights required for any use of the
|
||||||
|
Work.
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
|
party to this document and has no duty or obligation with respect to
|
||||||
|
this CC0 or use of the Work.
|
74
src/libs/3rdparty/tl_expected/README.md
vendored
Normal file
74
src/libs/3rdparty/tl_expected/README.md
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# expected
|
||||||
|
Single header implementation of `std::expected` with functional-style extensions.
|
||||||
|
|
||||||
|
[](https://tl.tartanllama.xyz/en/latest/?badge=latest)
|
||||||
|
Clang + GCC: [](https://github.com/TartanLlama/expected/actions/workflows/cmake.yml)
|
||||||
|
MSVC: [](https://ci.appveyor.com/project/TartanLlama/expected)
|
||||||
|
|
||||||
|
Available on [Vcpkg](https://github.com/microsoft/vcpkg/tree/master/ports/tl-expected) and [Conan](https://github.com/yipdw/conan-tl-expected).
|
||||||
|
|
||||||
|
[`std::expected`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf) is proposed as the preferred way to represent object which will either have an expected value, or an unexpected value giving information about why something failed. Unfortunately, chaining together many computations which may fail can be verbose, as error-checking code will be mixed in with the actual programming logic. This implementation provides a number of utilities to make coding with `expected` cleaner.
|
||||||
|
|
||||||
|
For example, instead of writing this code:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::expected<image,fail_reason> get_cute_cat (const image& img) {
|
||||||
|
auto cropped = crop_to_cat(img);
|
||||||
|
if (!cropped) {
|
||||||
|
return cropped;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto with_tie = add_bow_tie(*cropped);
|
||||||
|
if (!with_tie) {
|
||||||
|
return with_tie;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto with_sparkles = make_eyes_sparkle(*with_tie);
|
||||||
|
if (!with_sparkles) {
|
||||||
|
return with_sparkles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return add_rainbow(make_smaller(*with_sparkles));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can do this:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
tl::expected<image,fail_reason> get_cute_cat (const image& img) {
|
||||||
|
return crop_to_cat(img)
|
||||||
|
.and_then(add_bow_tie)
|
||||||
|
.and_then(make_eyes_sparkle)
|
||||||
|
.map(make_smaller)
|
||||||
|
.map(add_rainbow);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The interface is the same as `std::expected` as proposed in [p0323r3](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf), but the following member functions are also defined. Explicit types are for clarity.
|
||||||
|
|
||||||
|
- `map`: carries out some operation on the stored object if there is one.
|
||||||
|
* `tl::expected<std::size_t,std::error_code> s = exp_string.map(&std::string::size);`
|
||||||
|
- `map_error`: carries out some operation on the unexpected object if there is one.
|
||||||
|
* `my_error_code translate_error (std::error_code);`
|
||||||
|
* `tl::expected<int,my_error_code> s = exp_int.map_error(translate_error);`
|
||||||
|
- `and_then`: like `map`, but for operations which return a `tl::expected`.
|
||||||
|
* `tl::expected<ast, fail_reason> parse (const std::string& s);`
|
||||||
|
* `tl::expected<ast, fail_reason> exp_ast = exp_string.and_then(parse);`
|
||||||
|
- `or_else`: calls some function if there is no value stored.
|
||||||
|
* `exp.or_else([] { throw std::runtime_error{"oh no"}; });`
|
||||||
|
|
||||||
|
### Compiler support
|
||||||
|
|
||||||
|
Tested on:
|
||||||
|
|
||||||
|
- Linux
|
||||||
|
* clang++ 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9, 10, 11
|
||||||
|
* g++ 4.8, 4.9, 5.5, 6.4, 7.5, 8, 9, 10
|
||||||
|
- Windows
|
||||||
|
* MSVC 2015, 2017, 2019, 2022
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
[]("http://creativecommons.org/publicdomain/zero/1.0/")
|
||||||
|
|
||||||
|
To the extent possible under law, [Sy Brand](https://twitter.com/TartanLlama) has waived all copyright and related or neighboring rights to the `expected` library. This work is published from: United Kingdom.
|
2342
src/libs/3rdparty/tl_expected/include/tl/expected.hpp
vendored
Normal file
2342
src/libs/3rdparty/tl_expected/include/tl/expected.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -875,7 +875,7 @@ static bool findNewQmlLibraryInPath(const Utils::FilePath &path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// found a new library!
|
// found a new library!
|
||||||
const std::optional<QByteArray> contents = qmldirFile.fileContents();
|
const expected_str<QByteArray> contents = qmldirFile.fileContents();
|
||||||
if (!contents)
|
if (!contents)
|
||||||
return false;
|
return false;
|
||||||
QString qmldirData = QString::fromUtf8(*contents);
|
QString qmldirData = QString::fromUtf8(*contents);
|
||||||
@@ -985,7 +985,7 @@ void ModelManagerInterface::parseLoop(QSet<Utils::FilePath> &scannedPaths,
|
|||||||
contents = entry.first;
|
contents = entry.first;
|
||||||
documentRevision = entry.second;
|
documentRevision = entry.second;
|
||||||
} else {
|
} else {
|
||||||
const std::optional<QByteArray> fileContents = fileName.fileContents();
|
const expected_str<QByteArray> fileContents = fileName.fileContents();
|
||||||
if (fileContents) {
|
if (fileContents) {
|
||||||
QTextStream ins(*fileContents);
|
QTextStream ins(*fileContents);
|
||||||
contents = ins.readAll();
|
contents = ins.readAll();
|
||||||
|
@@ -42,6 +42,7 @@ add_qtc_library(Utils
|
|||||||
environmentmodel.cpp environmentmodel.h
|
environmentmodel.cpp environmentmodel.h
|
||||||
execmenu.cpp execmenu.h
|
execmenu.cpp execmenu.h
|
||||||
executeondestruction.h
|
executeondestruction.h
|
||||||
|
expected.h
|
||||||
fadingindicator.cpp fadingindicator.h
|
fadingindicator.cpp fadingindicator.h
|
||||||
faketooltip.cpp faketooltip.h
|
faketooltip.cpp faketooltip.h
|
||||||
fancylineedit.cpp fancylineedit.h
|
fancylineedit.cpp fancylineedit.h
|
||||||
|
@@ -6,8 +6,10 @@
|
|||||||
#include "algorithm.h"
|
#include "algorithm.h"
|
||||||
#include "commandline.h"
|
#include "commandline.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "expected.h"
|
||||||
#include "hostosinfo.h"
|
#include "hostosinfo.h"
|
||||||
#include "qtcassert.h"
|
#include "qtcassert.h"
|
||||||
|
#include "utilstr.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QOperatingSystemVersion>
|
#include <QOperatingSystemVersion>
|
||||||
@@ -18,8 +20,8 @@
|
|||||||
#ifdef QTCREATOR_PCH_H
|
#ifdef QTCREATOR_PCH_H
|
||||||
#define CALLBACK WINAPI
|
#define CALLBACK WINAPI
|
||||||
#endif
|
#endif
|
||||||
#include <qt_windows.h>
|
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
#include <qt_windows.h>
|
||||||
#else
|
#else
|
||||||
#include <qplatformdefs.h>
|
#include <qplatformdefs.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -137,12 +139,13 @@ bool DeviceFileAccess::removeRecursively(const FilePath &filePath, QString *erro
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
expected_str<void> DeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(filePath)
|
Q_UNUSED(filePath)
|
||||||
Q_UNUSED(target)
|
Q_UNUSED(target)
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
return false;
|
return make_unexpected(
|
||||||
|
Tr::tr("copyFile is not implemented for \"%1\"").arg(filePath.toUserOutput()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
bool DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
@@ -166,8 +169,7 @@ FilePath DeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceFileAccess::iterateDirectory(
|
void DeviceFileAccess::iterateDirectory(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
const FilePath::IterateDirCallback &callBack,
|
||||||
const FileFilter &filter) const
|
const FileFilter &filter) const
|
||||||
{
|
{
|
||||||
@@ -177,8 +179,7 @@ void DeviceFileAccess::iterateDirectory(
|
|||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> DeviceFileAccess::fileContents(
|
expected_str<QByteArray> DeviceFileAccess::fileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
@@ -186,11 +187,11 @@ std::optional<QByteArray> DeviceFileAccess::fileContents(
|
|||||||
Q_UNUSED(limit)
|
Q_UNUSED(limit)
|
||||||
Q_UNUSED(offset)
|
Q_UNUSED(offset)
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
return {};
|
return make_unexpected(
|
||||||
|
Tr::tr("fileContents is not implemented for \"%1\"").arg(filePath.toUserOutput()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceFileAccess::writeFileContents(
|
expected_str<qint64> DeviceFileAccess::writeFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
@@ -198,7 +199,8 @@ bool DeviceFileAccess::writeFileContents(
|
|||||||
Q_UNUSED(data)
|
Q_UNUSED(data)
|
||||||
Q_UNUSED(offset)
|
Q_UNUSED(offset)
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
return false;
|
return make_unexpected(
|
||||||
|
Tr::tr("writeFileContents is not implemented for \"%1\"").arg(filePath.toUserOutput()));
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePathInfo DeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
FilePathInfo DeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
||||||
@@ -251,8 +253,7 @@ QByteArray DeviceFileAccess::fileId(const FilePath &filePath) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FilePath> DeviceFileAccess::refersToExecutableFile(
|
std::optional<FilePath> DeviceFileAccess::refersToExecutableFile(
|
||||||
const FilePath &filePath,
|
const FilePath &filePath, FilePath::MatchScope matchScope) const
|
||||||
FilePath::MatchScope matchScope) const
|
|
||||||
{
|
{
|
||||||
Q_UNUSED(matchScope)
|
Q_UNUSED(matchScope)
|
||||||
if (isExecutableFile(filePath))
|
if (isExecutableFile(filePath))
|
||||||
@@ -260,33 +261,29 @@ std::optional<FilePath> DeviceFileAccess::refersToExecutableFile(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceFileAccess::asyncFileContents(
|
void DeviceFileAccess::asyncFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
const Continuation<expected_str<QByteArray>> &cont,
|
||||||
const Continuation<std::optional<QByteArray>> &cont,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
cont(fileContents(filePath, limit, offset));
|
cont(fileContents(filePath, limit, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceFileAccess::asyncWriteFileContents(
|
void DeviceFileAccess::asyncWriteFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
const Continuation<expected_str<qint64>> &cont,
|
||||||
const Continuation<bool> &cont,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
cont(writeFileContents(filePath, data, offset));
|
cont(writeFileContents(filePath, data, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceFileAccess::asyncCopyFile(
|
void DeviceFileAccess::asyncCopyFile(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
const Continuation<expected_str<void>> &cont,
|
||||||
const Continuation<bool> &cont,
|
|
||||||
const FilePath &target) const
|
const FilePath &target) const
|
||||||
{
|
{
|
||||||
cont(copyFile(filePath, target));
|
cont(copyFile(filePath, target));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DesktopDeviceFileAccess
|
// DesktopDeviceFileAccess
|
||||||
|
|
||||||
DesktopDeviceFileAccess::~DesktopDeviceFileAccess() = default;
|
DesktopDeviceFileAccess::~DesktopDeviceFileAccess() = default;
|
||||||
@@ -303,8 +300,8 @@ bool DesktopDeviceFileAccess::isExecutableFile(const FilePath &filePath) const
|
|||||||
return fi.isExecutable() && !fi.isDir();
|
return fi.isExecutable() && !fi.isDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<FilePath> isWindowsExecutableHelper
|
static std::optional<FilePath> isWindowsExecutableHelper(const FilePath &filePath,
|
||||||
(const FilePath &filePath, const QStringView suffix)
|
const QStringView suffix)
|
||||||
{
|
{
|
||||||
const QFileInfo fi(filePath.path().append(suffix));
|
const QFileInfo fi(filePath.path().append(suffix));
|
||||||
if (!fi.isExecutable() || fi.isDir())
|
if (!fi.isExecutable() || fi.isDir())
|
||||||
@@ -314,8 +311,7 @@ static std::optional<FilePath> isWindowsExecutableHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FilePath> DesktopDeviceFileAccess::refersToExecutableFile(
|
std::optional<FilePath> DesktopDeviceFileAccess::refersToExecutableFile(
|
||||||
const FilePath &filePath,
|
const FilePath &filePath, FilePath::MatchScope matchScope) const
|
||||||
FilePath::MatchScope matchScope) const
|
|
||||||
{
|
{
|
||||||
if (isExecutableFile(filePath))
|
if (isExecutableFile(filePath))
|
||||||
return filePath;
|
return filePath;
|
||||||
@@ -444,15 +440,16 @@ bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QStrin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList fileNames = dir.entryList(
|
const QStringList fileNames = dir.entryList(QDir::Files | QDir::Hidden | QDir::System
|
||||||
QDir::Files | QDir::Hidden | QDir::System | QDir::Dirs | QDir::NoDotAndDotDot);
|
| QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
for (const QString &fileName : fileNames) {
|
for (const QString &fileName : fileNames) {
|
||||||
if (!removeRecursively(filePath / fileName, error))
|
if (!removeRecursively(filePath / fileName, error))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!QDir::root().rmdir(dir.path())) {
|
if (!QDir::root().rmdir(dir.path())) {
|
||||||
if (error) {
|
if (error) {
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove directory \"%1\".")
|
*error = QCoreApplication::translate("Utils::FileUtils",
|
||||||
|
"Failed to remove directory \"%1\".")
|
||||||
.arg(filePath.toUserOutput());
|
.arg(filePath.toUserOutput());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -460,7 +457,8 @@ bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QStrin
|
|||||||
} else {
|
} else {
|
||||||
if (!QFile::remove(filePath.path())) {
|
if (!QFile::remove(filePath.path())) {
|
||||||
if (error) {
|
if (error) {
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove file \"%1\".")
|
*error = QCoreApplication::translate("Utils::FileUtils",
|
||||||
|
"Failed to remove file \"%1\".")
|
||||||
.arg(filePath.toUserOutput());
|
.arg(filePath.toUserOutput());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -469,9 +467,14 @@ bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QStrin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
expected_str<void> DesktopDeviceFileAccess::copyFile(const FilePath &filePath,
|
||||||
|
const FilePath &target) const
|
||||||
{
|
{
|
||||||
return QFile::copy(filePath.path(), target.path());
|
if (QFile::copy(filePath.path(), target.path()))
|
||||||
|
return {};
|
||||||
|
return make_unexpected(Tr::tr("Failed to copy file \"%1\" to \"%2\".")
|
||||||
|
.arg(filePath.toUserOutput())
|
||||||
|
.arg(target.toUserOutput()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
bool DesktopDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
@@ -514,8 +517,7 @@ FilePath DesktopDeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
|||||||
return FilePath::fromString(info.symLinkTarget());
|
return FilePath::fromString(info.symLinkTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopDeviceFileAccess::iterateDirectory(
|
void DesktopDeviceFileAccess::iterateDirectory(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
const FilePath::IterateDirCallback &callBack,
|
||||||
const FileFilter &filter) const
|
const FileFilter &filter) const
|
||||||
{
|
{
|
||||||
@@ -532,18 +534,17 @@ void DesktopDeviceFileAccess::iterateDirectory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> DesktopDeviceFileAccess::fileContents(
|
expected_str<QByteArray> DesktopDeviceFileAccess::fileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
const QString path = filePath.path();
|
const QString path = filePath.path();
|
||||||
QFile f(path);
|
QFile f(path);
|
||||||
if (!f.exists())
|
if (!f.exists())
|
||||||
return {};
|
return make_unexpected(Tr::tr("File \"%1\" does not exist").arg(path));
|
||||||
|
|
||||||
if (!f.open(QFile::ReadOnly))
|
if (!f.open(QFile::ReadOnly))
|
||||||
return {};
|
return make_unexpected(Tr::tr("Could not open File \"%1\"").arg(path));
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
f.seek(offset);
|
f.seek(offset);
|
||||||
@@ -551,21 +552,35 @@ std::optional<QByteArray> DesktopDeviceFileAccess::fileContents(
|
|||||||
if (limit != -1)
|
if (limit != -1)
|
||||||
return f.read(limit);
|
return f.read(limit);
|
||||||
|
|
||||||
return f.readAll();
|
const QByteArray data = f.readAll();
|
||||||
|
if (f.error() != QFile::NoError) {
|
||||||
|
return make_unexpected(
|
||||||
|
Tr::tr("Cannot read \"%1\": %2").arg(filePath.toUserOutput(), f.errorString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopDeviceFileAccess::writeFileContents(
|
return data;
|
||||||
const FilePath &filePath,
|
}
|
||||||
|
|
||||||
|
expected_str<qint64> DesktopDeviceFileAccess::writeFileContents(const FilePath &filePath,
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
QFile file(filePath.path());
|
QFile file(filePath.path());
|
||||||
const bool isOpened = file.open(QFile::WriteOnly | QFile::Truncate);
|
const bool isOpened = file.open(QFile::WriteOnly | QFile::Truncate);
|
||||||
QTC_ASSERT(isOpened, return false);
|
if (!isOpened)
|
||||||
|
return make_unexpected(
|
||||||
|
Tr::tr("Could not open file \"%1\" for writing").arg(filePath.toUserOutput()));
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
file.seek(offset);
|
file.seek(offset);
|
||||||
qint64 res = file.write(data);
|
qint64 res = file.write(data);
|
||||||
return res == data.size();
|
if (res != data.size())
|
||||||
|
return make_unexpected(
|
||||||
|
Tr::tr("Could not write to file \"%1\" (only %2 of %3 bytes written)")
|
||||||
|
.arg(filePath.toUserOutput())
|
||||||
|
.arg(res)
|
||||||
|
.arg(data.size()));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime DesktopDeviceFileAccess::lastModified(const FilePath &filePath) const
|
QDateTime DesktopDeviceFileAccess::lastModified(const FilePath &filePath) const
|
||||||
@@ -603,7 +618,9 @@ static inline QByteArray fileIdWin7(HANDLE handle)
|
|||||||
BY_HANDLE_FILE_INFORMATION info;
|
BY_HANDLE_FILE_INFORMATION info;
|
||||||
if (GetFileInformationByHandle(handle, &info)) {
|
if (GetFileInformationByHandle(handle, &info)) {
|
||||||
char buffer[sizeof "01234567:0123456701234567\0"];
|
char buffer[sizeof "01234567:0123456701234567\0"];
|
||||||
qsnprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx",
|
qsnprintf(buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"%lx:%08lx%08lx",
|
||||||
info.dwVolumeSerialNumber,
|
info.dwVolumeSerialNumber,
|
||||||
info.nFileIndexHigh,
|
info.nFileIndexHigh,
|
||||||
info.nFileIndexLow);
|
info.nFileIndexLow);
|
||||||
@@ -618,20 +635,25 @@ static QByteArray fileIdWin8(HANDLE handle)
|
|||||||
QByteArray result;
|
QByteArray result;
|
||||||
FILE_ID_INFO infoEx;
|
FILE_ID_INFO infoEx;
|
||||||
if (GetFileInformationByHandleEx(handle,
|
if (GetFileInformationByHandleEx(handle,
|
||||||
static_cast<FILE_INFO_BY_HANDLE_CLASS>(18), // FileIdInfo in Windows 8
|
static_cast<FILE_INFO_BY_HANDLE_CLASS>(
|
||||||
&infoEx, sizeof(FILE_ID_INFO))) {
|
18), // FileIdInfo in Windows 8
|
||||||
|
&infoEx,
|
||||||
|
sizeof(FILE_ID_INFO))) {
|
||||||
result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
|
result = QByteArray::number(infoEx.VolumeSerialNumber, 16);
|
||||||
result += ':';
|
result += ':';
|
||||||
// Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one.
|
// Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one.
|
||||||
result += QByteArray(reinterpret_cast<const char *>(&infoEx.FileId), int(sizeof(infoEx.FileId))).toHex();
|
result += QByteArray(reinterpret_cast<const char *>(&infoEx.FileId),
|
||||||
|
int(sizeof(infoEx.FileId)))
|
||||||
|
.toHex();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QByteArray fileIdWin(HANDLE fHandle)
|
static QByteArray fileIdWin(HANDLE fHandle)
|
||||||
{
|
{
|
||||||
return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
|
return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8
|
||||||
fileIdWin8(HANDLE(fHandle)) : fileIdWin7(HANDLE(fHandle));
|
? fileIdWin8(HANDLE(fHandle))
|
||||||
|
: fileIdWin7(HANDLE(fHandle));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -640,10 +662,13 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const
|
|||||||
QByteArray result;
|
QByteArray result;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
const HANDLE handle =
|
const HANDLE handle = CreateFile((wchar_t *) filePath.toUserOutput().utf16(),
|
||||||
CreateFile((wchar_t*)filePath.toUserOutput().utf16(), 0,
|
0,
|
||||||
FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
FILE_SHARE_READ,
|
||||||
FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
|
NULL);
|
||||||
if (handle != INVALID_HANDLE_VALUE) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
result = fileIdWin(handle);
|
result = fileIdWin(handle);
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
@@ -668,7 +693,6 @@ OsType DesktopDeviceFileAccess::osType(const FilePath &filePath) const
|
|||||||
return HostOsInfo::hostOs();
|
return HostOsInfo::hostOs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// UnixDeviceAccess
|
// UnixDeviceAccess
|
||||||
|
|
||||||
UnixDeviceFileAccess::~UnixDeviceFileAccess() = default;
|
UnixDeviceFileAccess::~UnixDeviceFileAccess() = default;
|
||||||
@@ -769,9 +793,19 @@ bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *
|
|||||||
return result.exitCode == 0;
|
return result.exitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
expected_str<void> UnixDeviceFileAccess::copyFile(const FilePath &filePath,
|
||||||
|
const FilePath &target) const
|
||||||
{
|
{
|
||||||
return runInShellSuccess({"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux});
|
const RunResult result = runInShell(
|
||||||
|
{"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux});
|
||||||
|
|
||||||
|
if (result.exitCode != 0) {
|
||||||
|
return make_unexpected(Tr::tr("Failed to copy file \"%1\" to \"%2\": %3")
|
||||||
|
.arg(filePath.toUserOutput())
|
||||||
|
.arg(target.toUserOutput())
|
||||||
|
.arg(QString::fromUtf8(result.stdErr)));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
@@ -781,13 +815,13 @@ bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &
|
|||||||
|
|
||||||
FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
const RunResult result = runInShell({"readlink", {"-n", "-e", filePath.path()}, OsType::OsTypeLinux});
|
const RunResult result = runInShell(
|
||||||
|
{"readlink", {"-n", "-e", filePath.path()}, OsType::OsTypeLinux});
|
||||||
const QString out = QString::fromUtf8(result.stdOut);
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
return out.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
return out.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> UnixDeviceFileAccess::fileContents(
|
expected_str<QByteArray> UnixDeviceFileAccess::fileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
@@ -802,13 +836,14 @@ std::optional<QByteArray> UnixDeviceFileAccess::fileContents(
|
|||||||
const RunResult r = runInShell({"dd", args, OsType::OsTypeLinux});
|
const RunResult r = runInShell({"dd", args, OsType::OsTypeLinux});
|
||||||
|
|
||||||
if (r.exitCode != 0)
|
if (r.exitCode != 0)
|
||||||
return {};
|
return make_unexpected(Tr::tr("Failed reading file \"%1\": %2")
|
||||||
|
.arg(filePath.toUserOutput())
|
||||||
|
.arg(QString::fromUtf8(r.stdErr)));
|
||||||
|
|
||||||
return r.stdOut;
|
return r.stdOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnixDeviceFileAccess::writeFileContents(
|
expected_str<qint64> UnixDeviceFileAccess::writeFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
@@ -817,7 +852,14 @@ bool UnixDeviceFileAccess::writeFileContents(
|
|||||||
args.append("bs=1");
|
args.append("bs=1");
|
||||||
args.append(QString("seek=%1").arg(offset));
|
args.append(QString("seek=%1").arg(offset));
|
||||||
}
|
}
|
||||||
return runInShellSuccess({"dd", args, OsType::OsTypeLinux}, data);
|
RunResult result = runInShell({"dd", args, OsType::OsTypeLinux}, data);
|
||||||
|
|
||||||
|
if (result.exitCode != 0) {
|
||||||
|
return make_unexpected(Tr::tr("Failed writing file \"%1\": %2")
|
||||||
|
.arg(filePath.toUserOutput())
|
||||||
|
.arg(QString::fromUtf8(result.stdErr)));
|
||||||
|
}
|
||||||
|
return data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const
|
OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const
|
||||||
@@ -828,7 +870,8 @@ OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const
|
|||||||
|
|
||||||
QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const
|
QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
const RunResult result = runInShell({"stat", {"-L", "-c", "%Y", filePath.path()}, OsType::OsTypeLinux});
|
const RunResult result = runInShell(
|
||||||
|
{"stat", {"-L", "-c", "%Y", filePath.path()}, OsType::OsTypeLinux});
|
||||||
qint64 secs = result.stdOut.toLongLong();
|
qint64 secs = result.stdOut.toLongLong();
|
||||||
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
||||||
return dt;
|
return dt;
|
||||||
@@ -836,10 +879,13 @@ QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const
|
|||||||
|
|
||||||
QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const
|
QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
const RunResult result = runInShell({"stat", {"-L", "-c", "%a", filePath.path()}, OsType::OsTypeLinux});
|
const RunResult result = runInShell(
|
||||||
|
{"stat", {"-L", "-c", "%a", filePath.path()}, OsType::OsTypeLinux});
|
||||||
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
||||||
QFileDevice::Permissions perm = {};
|
QFileDevice::Permissions perm = {};
|
||||||
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
#define BIT(n, p) \
|
||||||
|
if (bits & (1 << n)) \
|
||||||
|
perm |= QFileDevice::p
|
||||||
BIT(0, ExeOther);
|
BIT(0, ExeOther);
|
||||||
BIT(1, WriteOther);
|
BIT(1, WriteOther);
|
||||||
BIT(2, ReadOther);
|
BIT(2, ReadOther);
|
||||||
@@ -856,12 +902,14 @@ QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) c
|
|||||||
bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const
|
bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const
|
||||||
{
|
{
|
||||||
const int flags = int(perms);
|
const int flags = int(perms);
|
||||||
return runInShellSuccess({"chmod", {QString::number(flags, 16), filePath.path()}, OsType::OsTypeLinux});
|
return runInShellSuccess(
|
||||||
|
{"chmod", {QString::number(flags, 16), filePath.path()}, OsType::OsTypeLinux});
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const
|
qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
const RunResult result = runInShell({"stat", {"-L", "-c", "%s", filePath.path()}, OsType::OsTypeLinux});
|
const RunResult result = runInShell(
|
||||||
|
{"stat", {"-L", "-c", "%s", filePath.path()}, OsType::OsTypeLinux});
|
||||||
return result.stdOut.toLongLong();
|
return result.stdOut.toLongLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,7 +921,8 @@ qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const
|
|||||||
|
|
||||||
QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const
|
QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
const RunResult result = runInShell({"stat", {"-L", "-c", "%D:%i", filePath.path()}, OsType::OsTypeLinux});
|
const RunResult result = runInShell(
|
||||||
|
{"stat", {"-L", "-c", "%D:%i", filePath.path()}, OsType::OsTypeLinux});
|
||||||
if (result.exitCode != 0)
|
if (result.exitCode != 0)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@@ -882,13 +931,13 @@ QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const
|
|||||||
|
|
||||||
FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
const RunResult stat = runInShell({"stat", {"-L", "-c", "%f %Y %s", filePath.path()}, OsType::OsTypeLinux});
|
const RunResult stat = runInShell(
|
||||||
|
{"stat", {"-L", "-c", "%f %Y %s", filePath.path()}, OsType::OsTypeLinux});
|
||||||
return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut));
|
return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut));
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns whether 'find' could be used.
|
// returns whether 'find' could be used.
|
||||||
bool UnixDeviceFileAccess::iterateWithFind(
|
bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
const FilePath::IterateDirCallback &callBack) const
|
const FilePath::IterateDirCallback &callBack) const
|
||||||
{
|
{
|
||||||
@@ -899,7 +948,8 @@ bool UnixDeviceFileAccess::iterateWithFind(
|
|||||||
// TODO: Using stat -L will always return the link target, not the link itself.
|
// TODO: Using stat -L will always return the link target, not the link itself.
|
||||||
// We may wan't to add the information that it is a link at some point.
|
// We may wan't to add the information that it is a link at some point.
|
||||||
if (callBack.index() == 1)
|
if (callBack.index() == 1)
|
||||||
cmdLine.addArgs(R"(-exec echo -n \"{}\"" " \; -exec stat -L -c "%f %Y %s" "{}" \;)", CommandLine::Raw);
|
cmdLine.addArgs(R"(-exec echo -n \"{}\"" " \; -exec stat -L -c "%f %Y %s" "{}" \;)",
|
||||||
|
CommandLine::Raw);
|
||||||
|
|
||||||
const RunResult result = runInShell(cmdLine);
|
const RunResult result = runInShell(cmdLine);
|
||||||
const QString out = QString::fromUtf8(result.stdOut);
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
@@ -951,8 +1001,7 @@ bool UnixDeviceFileAccess::iterateWithFind(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnixDeviceFileAccess::findUsingLs(
|
void UnixDeviceFileAccess::findUsingLs(const QString ¤t,
|
||||||
const QString ¤t,
|
|
||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
QStringList *found) const
|
QStringList *found) const
|
||||||
{
|
{
|
||||||
@@ -975,8 +1024,8 @@ static void iterateLsOutput(const FilePath &base,
|
|||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
const FilePath::IterateDirCallback &callBack)
|
const FilePath::IterateDirCallback &callBack)
|
||||||
{
|
{
|
||||||
const QList<QRegularExpression> nameRegexps =
|
const QList<QRegularExpression> nameRegexps
|
||||||
transform(filter.nameFilters, [](const QString &filter) {
|
= transform(filter.nameFilters, [](const QString &filter) {
|
||||||
QRegularExpression re;
|
QRegularExpression re;
|
||||||
re.setPattern(QRegularExpression::wildcardToRegularExpression(filter));
|
re.setPattern(QRegularExpression::wildcardToRegularExpression(filter));
|
||||||
QTC_CHECK(re.isValid());
|
QTC_CHECK(re.isValid());
|
||||||
@@ -1009,8 +1058,7 @@ static void iterateLsOutput(const FilePath &base,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnixDeviceFileAccess::iterateDirectory(
|
void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
const FilePath::IterateDirCallback &callBack,
|
||||||
const FileFilter &filter) const
|
const FileFilter &filter) const
|
||||||
{
|
{
|
||||||
@@ -1019,7 +1067,8 @@ void UnixDeviceFileAccess::iterateDirectory(
|
|||||||
if (m_tryUseFind) {
|
if (m_tryUseFind) {
|
||||||
if (iterateWithFind(filePath, filter, callBack))
|
if (iterateWithFind(filePath, filter, callBack))
|
||||||
return;
|
return;
|
||||||
m_tryUseFind = false; // remember the failure for the next time and use the 'ls' fallback below.
|
m_tryUseFind
|
||||||
|
= false; // remember the failure for the next time and use the 'ls' fallback below.
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we do not have find - use ls as fallback
|
// if we do not have find - use ls as fallback
|
||||||
@@ -1028,4 +1077,4 @@ void UnixDeviceFileAccess::iterateDirectory(
|
|||||||
iterateLsOutput(filePath, entries, filter, callBack);
|
iterateLsOutput(filePath, entries, filter, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Utils
|
} // namespace Utils
|
||||||
|
@@ -34,7 +34,7 @@ protected:
|
|||||||
virtual bool exists(const FilePath &filePath) const;
|
virtual bool exists(const FilePath &filePath) const;
|
||||||
virtual bool removeFile(const FilePath &filePath) const;
|
virtual bool removeFile(const FilePath &filePath) const;
|
||||||
virtual bool removeRecursively(const FilePath &filePath, QString *error) const;
|
virtual bool removeRecursively(const FilePath &filePath, QString *error) const;
|
||||||
virtual bool copyFile(const FilePath &filePath, const FilePath &target) const;
|
virtual expected_str<void> copyFile(const FilePath &filePath, const FilePath &target) const;
|
||||||
virtual bool renameFile(const FilePath &filePath, const FilePath &target) const;
|
virtual bool renameFile(const FilePath &filePath, const FilePath &target) const;
|
||||||
|
|
||||||
virtual OsType osType(const FilePath &filePath) const;
|
virtual OsType osType(const FilePath &filePath) const;
|
||||||
@@ -56,30 +56,26 @@ protected:
|
|||||||
const FilePath::IterateDirCallback &callBack,
|
const FilePath::IterateDirCallback &callBack,
|
||||||
const FileFilter &filter) const;
|
const FileFilter &filter) const;
|
||||||
|
|
||||||
virtual std::optional<QByteArray> fileContents(
|
virtual expected_str<QByteArray> fileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const;
|
|
||||||
virtual bool writeFileContents(
|
|
||||||
const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const;
|
|
||||||
|
|
||||||
virtual void asyncFileContents(
|
|
||||||
const FilePath &filePath,
|
|
||||||
const Continuation<std::optional<QByteArray>> &cont,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const;
|
qint64 offset) const;
|
||||||
|
|
||||||
virtual void asyncWriteFileContents(
|
virtual expected_str<qint64> writeFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const Continuation<bool> &cont,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const;
|
qint64 offset) const;
|
||||||
|
|
||||||
virtual void asyncCopyFile(
|
virtual void asyncFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
const Continuation<expected_str<QByteArray>> &cont,
|
||||||
const Continuation<bool> &cont,
|
qint64 limit,
|
||||||
|
qint64 offset) const;
|
||||||
|
|
||||||
|
virtual void asyncWriteFileContents(const FilePath &filePath,
|
||||||
|
const Continuation<expected_str<qint64>> &cont,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const;
|
||||||
|
|
||||||
|
virtual void asyncCopyFile(const FilePath &filePath,
|
||||||
|
const Continuation<expected_str<void>> &cont,
|
||||||
const FilePath &target) const;
|
const FilePath &target) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,7 +101,7 @@ protected:
|
|||||||
bool exists(const FilePath &filePath) const override;
|
bool exists(const FilePath &filePath) const override;
|
||||||
bool removeFile(const FilePath &filePath) const override;
|
bool removeFile(const FilePath &filePath) const override;
|
||||||
bool removeRecursively(const FilePath &filePath, QString *error) const override;
|
bool removeRecursively(const FilePath &filePath, QString *error) const override;
|
||||||
bool copyFile(const FilePath &filePath, const FilePath &target) const override;
|
expected_str<void> copyFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
bool renameFile(const FilePath &filePath, const FilePath &target) const override;
|
bool renameFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
|
|
||||||
OsType osType(const FilePath &filePath) const override;
|
OsType osType(const FilePath &filePath) const override;
|
||||||
@@ -127,12 +123,10 @@ protected:
|
|||||||
const FilePath::IterateDirCallback &callBack,
|
const FilePath::IterateDirCallback &callBack,
|
||||||
const FileFilter &filter) const override;
|
const FileFilter &filter) const override;
|
||||||
|
|
||||||
std::optional<QByteArray> fileContents(
|
expected_str<QByteArray> fileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const override;
|
qint64 offset) const override;
|
||||||
bool writeFileContents(
|
expected_str<qint64> writeFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const override;
|
qint64 offset) const override;
|
||||||
};
|
};
|
||||||
@@ -160,7 +154,7 @@ protected:
|
|||||||
bool exists(const FilePath &filePath) const override;
|
bool exists(const FilePath &filePath) const override;
|
||||||
bool removeFile(const FilePath &filePath) const override;
|
bool removeFile(const FilePath &filePath) const override;
|
||||||
bool removeRecursively(const FilePath &filePath, QString *error) const override;
|
bool removeRecursively(const FilePath &filePath, QString *error) const override;
|
||||||
bool copyFile(const FilePath &filePath, const FilePath &target) const override;
|
expected_str<void> copyFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
bool renameFile(const FilePath &filePath, const FilePath &target) const override;
|
bool renameFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
|
|
||||||
FilePathInfo filePathInfo(const FilePath &filePath) const override;
|
FilePathInfo filePathInfo(const FilePath &filePath) const override;
|
||||||
@@ -178,12 +172,10 @@ protected:
|
|||||||
const FilePath::IterateDirCallback &callBack,
|
const FilePath::IterateDirCallback &callBack,
|
||||||
const FileFilter &filter) const override;
|
const FileFilter &filter) const override;
|
||||||
|
|
||||||
std::optional<QByteArray> fileContents(
|
expected_str<QByteArray> fileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const override;
|
qint64 offset) const override;
|
||||||
bool writeFileContents(
|
expected_str<qint64> writeFileContents(const FilePath &filePath,
|
||||||
const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const override;
|
qint64 offset) const override;
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "elfreader.h"
|
#include "elfreader.h"
|
||||||
|
|
||||||
|
#include "expected.h"
|
||||||
#include "qtcassert.h"
|
#include "qtcassert.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@@ -85,7 +86,9 @@ ElfMapper::ElfMapper(const ElfReader *reader)
|
|||||||
bool ElfMapper::map()
|
bool ElfMapper::map()
|
||||||
{
|
{
|
||||||
if (binary.needsDevice()) {
|
if (binary.needsDevice()) {
|
||||||
raw = binary.fileContents().value_or(QByteArray());
|
const expected_str<QByteArray> contents = binary.fileContents();
|
||||||
|
QTC_CHECK(contents);
|
||||||
|
raw = contents.value_or(QByteArray());
|
||||||
start = raw.constData();
|
start = raw.constData();
|
||||||
fdlen = raw.size();
|
fdlen = raw.size();
|
||||||
return fdlen > 0;
|
return fdlen > 0;
|
||||||
|
47
src/libs/utils/expected.h
Normal file
47
src/libs/utils/expected.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qtcassert.h"
|
||||||
|
|
||||||
|
#include "../3rdparty/tl_expected/include/tl/expected.hpp"
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
template<class T, class E>
|
||||||
|
using expected = tl::expected<T, E>;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
using expected_str = tl::expected<T, QString>;
|
||||||
|
|
||||||
|
template<class E>
|
||||||
|
using unexpected = tl::unexpected<E>;
|
||||||
|
using unexpect_t = tl::unexpect_t;
|
||||||
|
|
||||||
|
static constexpr unexpect_t unexpect{};
|
||||||
|
|
||||||
|
template<class E>
|
||||||
|
constexpr unexpected<std::decay_t<E>> make_unexpected(E &&e)
|
||||||
|
{
|
||||||
|
return tl::make_unexpected(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Utils
|
||||||
|
|
||||||
|
//! If 'expected' has an error the error will be printed and the 'action' will be executed.
|
||||||
|
#define QTC_ASSERT_EXPECTED(expected, action) \
|
||||||
|
{ \
|
||||||
|
if (Q_LIKELY(expected)) { \
|
||||||
|
} else { \
|
||||||
|
::Utils::writeAssertLocation(QString("%1:%2: %3") \
|
||||||
|
.arg(__FILE__) \
|
||||||
|
.arg(__LINE__) \
|
||||||
|
.arg(expected.error()) \
|
||||||
|
.toUtf8() \
|
||||||
|
.data()); \
|
||||||
|
action; \
|
||||||
|
} \
|
||||||
|
do { \
|
||||||
|
} while (0); \
|
||||||
|
}
|
@@ -9,15 +9,17 @@
|
|||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "hostosinfo.h"
|
#include "hostosinfo.h"
|
||||||
#include "qtcassert.h"
|
#include "qtcassert.h"
|
||||||
|
#include "utilstr.h"
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QByteArray>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QUrl>
|
|
||||||
#include <QStringView>
|
#include <QStringView>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#ifdef QTCREATOR_PCH_H
|
#ifdef QTCREATOR_PCH_H
|
||||||
@@ -494,7 +496,7 @@ void FilePath::iterateDirectories(const FilePaths &dirs,
|
|||||||
dir.iterateDirectory(callBack, filter);
|
dir.iterateDirectory(callBack, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> FilePath::fileContents(qint64 maxSize, qint64 offset) const
|
expected_str<QByteArray> FilePath::fileContents(qint64 maxSize, qint64 offset) const
|
||||||
{
|
{
|
||||||
return fileAccess()->fileContents(*this, maxSize, offset);
|
return fileAccess()->fileContents(*this, maxSize, offset);
|
||||||
}
|
}
|
||||||
@@ -510,15 +512,14 @@ bool FilePath::ensureReachable(const FilePath &other) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePath::asyncFileContents(
|
void FilePath::asyncFileContents(const Continuation<const expected_str<QByteArray> &> &cont,
|
||||||
const Continuation<const std::optional<QByteArray> &> &cont,
|
|
||||||
qint64 maxSize,
|
qint64 maxSize,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
return fileAccess()->asyncFileContents(*this, cont, maxSize, offset);
|
return fileAccess()->asyncFileContents(*this, cont, maxSize, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::writeFileContents(const QByteArray &data, qint64 offset) const
|
expected_str<qint64> FilePath::writeFileContents(const QByteArray &data, qint64 offset) const
|
||||||
{
|
{
|
||||||
return fileAccess()->writeFileContents(*this, data, offset);
|
return fileAccess()->writeFileContents(*this, data, offset);
|
||||||
}
|
}
|
||||||
@@ -528,8 +529,7 @@ FilePathInfo FilePath::filePathInfo() const
|
|||||||
return fileAccess()->filePathInfo(*this);
|
return fileAccess()->filePathInfo(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePath::asyncWriteFileContents(
|
void FilePath::asyncWriteFileContents(const Continuation<const expected_str<qint64> &> &cont,
|
||||||
const Continuation<bool> &cont,
|
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
@@ -1315,33 +1315,47 @@ bool FilePath::removeRecursively(QString *error) const
|
|||||||
return fileAccess()->removeRecursively(*this, error);
|
return fileAccess()->removeRecursively(*this, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::copyFile(const FilePath &target) const
|
expected_str<void> FilePath::copyFile(const FilePath &target) const
|
||||||
{
|
{
|
||||||
if (host() != target.host()) {
|
if (host() != target.host()) {
|
||||||
// FIXME: This does not scale.
|
// FIXME: This does not scale.
|
||||||
const std::optional<QByteArray> ba = fileContents();
|
const expected_str<QByteArray> contents = fileContents();
|
||||||
if (!ba)
|
if (!contents) {
|
||||||
return false;
|
return make_unexpected(
|
||||||
const auto perms = permissions();
|
Tr::tr("Error while trying to copy file: %1").arg(contents.error()));
|
||||||
if (!target.writeFileContents(*ba))
|
}
|
||||||
return false;
|
|
||||||
|
const QFile::Permissions perms = permissions();
|
||||||
|
const expected_str<qint64> copyResult = target.writeFileContents(*contents);
|
||||||
|
|
||||||
|
if (!copyResult)
|
||||||
|
return make_unexpected(Tr::tr("Could not copy file: %1").arg(copyResult.error()));
|
||||||
|
|
||||||
if (!target.setPermissions(perms)) {
|
if (!target.setPermissions(perms)) {
|
||||||
target.removeFile();
|
target.removeFile();
|
||||||
return false;
|
return make_unexpected(
|
||||||
|
Tr::tr("Could not set permissions on \"%1\"").arg(target.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
return fileAccess()->copyFile(*this, target);
|
return fileAccess()->copyFile(*this, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePath::asyncCopyFile(const std::function<void(bool)> &cont, const FilePath &target) const
|
void FilePath::asyncCopyFile(const Continuation<const expected_str<void> &> &cont,
|
||||||
|
const FilePath &target) const
|
||||||
{
|
{
|
||||||
if (host() != target.host()) {
|
if (host() != target.host()) {
|
||||||
asyncFileContents([cont, target](const std::optional<QByteArray> &ba) {
|
asyncFileContents([cont, target](const expected_str<QByteArray> &contents) {
|
||||||
if (ba)
|
if (contents)
|
||||||
target.asyncWriteFileContents(cont, *ba);
|
target.asyncWriteFileContents(
|
||||||
|
[cont](const expected_str<qint64> &result) {
|
||||||
|
if (result)
|
||||||
|
cont({});
|
||||||
|
else
|
||||||
|
cont(make_unexpected(result.error()));
|
||||||
|
},
|
||||||
|
*contents);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "utils_global.h"
|
#include "utils_global.h"
|
||||||
|
|
||||||
|
#include "expected.h"
|
||||||
#include "filepathinfo.h"
|
#include "filepathinfo.h"
|
||||||
#include "osspecificaspects.h"
|
#include "osspecificaspects.h"
|
||||||
|
|
||||||
@@ -119,15 +120,15 @@ public:
|
|||||||
OsType osType() const;
|
OsType osType() const;
|
||||||
bool removeFile() const;
|
bool removeFile() const;
|
||||||
bool removeRecursively(QString *error = nullptr) const;
|
bool removeRecursively(QString *error = nullptr) const;
|
||||||
bool copyFile(const FilePath &target) const;
|
expected_str<void> copyFile(const FilePath &target) const;
|
||||||
bool renameFile(const FilePath &target) const;
|
bool renameFile(const FilePath &target) const;
|
||||||
qint64 fileSize() const;
|
qint64 fileSize() const;
|
||||||
qint64 bytesAvailable() const;
|
qint64 bytesAvailable() const;
|
||||||
bool createDir() const;
|
bool createDir() const;
|
||||||
FilePaths dirEntries(const FileFilter &filter, QDir::SortFlags sort = QDir::NoSort) const;
|
FilePaths dirEntries(const FileFilter &filter, QDir::SortFlags sort = QDir::NoSort) const;
|
||||||
FilePaths dirEntries(QDir::Filters filters) const;
|
FilePaths dirEntries(QDir::Filters filters) const;
|
||||||
std::optional<QByteArray> fileContents(qint64 maxSize = -1, qint64 offset = 0) const;
|
expected_str<QByteArray> fileContents(qint64 maxSize = -1, qint64 offset = 0) const;
|
||||||
bool writeFileContents(const QByteArray &data, qint64 offset = 0) const;
|
expected_str<qint64> writeFileContents(const QByteArray &data, qint64 offset = 0) const;
|
||||||
FilePathInfo filePathInfo() const;
|
FilePathInfo filePathInfo() const;
|
||||||
|
|
||||||
bool operator==(const FilePath &other) const;
|
bool operator==(const FilePath &other) const;
|
||||||
@@ -198,11 +199,12 @@ public:
|
|||||||
static void sort(FilePaths &files);
|
static void sort(FilePaths &files);
|
||||||
|
|
||||||
// Asynchronous interface
|
// Asynchronous interface
|
||||||
void asyncCopyFile(const Continuation<bool> &cont, const FilePath &target) const;
|
void asyncCopyFile(const Continuation<const expected_str<void> &> &cont,
|
||||||
void asyncFileContents(const Continuation<const std::optional<QByteArray> &> &cont,
|
const FilePath &target) const;
|
||||||
|
void asyncFileContents(const Continuation<const expected_str<QByteArray> &> &cont,
|
||||||
qint64 maxSize = -1,
|
qint64 maxSize = -1,
|
||||||
qint64 offset = 0) const;
|
qint64 offset = 0) const;
|
||||||
void asyncWriteFileContents(const Continuation<bool> &cont,
|
void asyncWriteFileContents(const Continuation<const expected_str<qint64> &> &cont,
|
||||||
const QByteArray &data,
|
const QByteArray &data,
|
||||||
qint64 offset = 0) const;
|
qint64 offset = 0) const;
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ static bool getFileContent(const FilePath &filePath,
|
|||||||
if (fileToContentsMap.contains(filePath)) {
|
if (fileToContentsMap.contains(filePath)) {
|
||||||
*tempString = fileToContentsMap.value(filePath);
|
*tempString = fileToContentsMap.value(filePath);
|
||||||
} else {
|
} else {
|
||||||
const std::optional<QByteArray> content = filePath.fileContents();
|
const expected_str<QByteArray> content = filePath.fileContents();
|
||||||
if (!content)
|
if (!content)
|
||||||
return false;
|
return false;
|
||||||
*tempString = QTC_GUARD(encoding) ? encoding->toUnicode(*content)
|
*tempString = QTC_GUARD(encoding) ? encoding->toUnicode(*content)
|
||||||
|
@@ -55,31 +55,15 @@ bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode)
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(!(mode & ~(QIODevice::ReadOnly | QIODevice::Text)), return false);
|
QTC_ASSERT(!(mode & ~(QIODevice::ReadOnly | QIODevice::Text)), return false);
|
||||||
|
|
||||||
if (filePath.needsDevice()) {
|
const expected_str<QByteArray> contents = filePath.fileContents();
|
||||||
const std::optional<QByteArray> contents = filePath.fileContents();
|
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
m_errorString = tr("Cannot read %1").arg(filePath.toUserOutput());
|
m_errorString = contents.error();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_data = *contents;
|
m_data = *contents;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile file(filePath.toString());
|
|
||||||
if (!file.open(QIODevice::ReadOnly | mode)) {
|
|
||||||
m_errorString = tr("Cannot open %1 for reading: %2").arg(
|
|
||||||
filePath.toUserOutput(), file.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_data = file.readAll();
|
|
||||||
if (file.error() != QFile::NoError) {
|
|
||||||
m_errorString = tr("Cannot read %1: %2").arg(
|
|
||||||
filePath.toUserOutput(), file.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QString *errorString)
|
bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QString *errorString)
|
||||||
{
|
{
|
||||||
if (fetch(filePath, mode))
|
if (fetch(filePath, mode))
|
||||||
@@ -225,10 +209,10 @@ bool FileSaver::finalize()
|
|||||||
m_file->close();
|
m_file->close();
|
||||||
m_file->open(QIODevice::ReadOnly);
|
m_file->open(QIODevice::ReadOnly);
|
||||||
const QByteArray data = m_file->readAll();
|
const QByteArray data = m_file->readAll();
|
||||||
const bool res = m_filePath.writeFileContents(data);
|
const expected_str<qint64> res = m_filePath.writeFileContents(data);
|
||||||
m_file->remove();
|
m_file->remove();
|
||||||
m_file.reset();
|
m_file.reset();
|
||||||
return res;
|
return res.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_isSafe)
|
if (!m_isSafe)
|
||||||
@@ -703,15 +687,20 @@ bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgt
|
|||||||
const QDateTime srcModified = srcFilePath.lastModified();
|
const QDateTime srcModified = srcFilePath.lastModified();
|
||||||
const QDateTime tgtModified = tgtFilePath.lastModified();
|
const QDateTime tgtModified = tgtFilePath.lastModified();
|
||||||
if (srcModified == tgtModified) {
|
if (srcModified == tgtModified) {
|
||||||
const std::optional<QByteArray> srcContents = srcFilePath.fileContents();
|
// TODO: Create FilePath::hashFromContents() and compare hashes.
|
||||||
const std::optional<QByteArray> tgtContents = srcFilePath.fileContents();
|
const expected_str<QByteArray> srcContents = srcFilePath.fileContents();
|
||||||
if (srcContents == tgtContents)
|
const expected_str<QByteArray> tgtContents = srcFilePath.fileContents();
|
||||||
|
if (srcContents && srcContents == tgtContents)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
tgtFilePath.removeFile();
|
tgtFilePath.removeFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
return srcFilePath.copyFile(tgtFilePath);
|
const expected_str<void> copyResult = srcFilePath.copyFile(tgtFilePath);
|
||||||
|
|
||||||
|
// TODO forward error to caller instead of assert, since IO errors can always be expected
|
||||||
|
QTC_ASSERT_EXPECTED(copyResult, return false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FileUtils::fileSystemFriendlyName(const QString &name)
|
QString FileUtils::fileSystemFriendlyName(const QString &name)
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include "fsengine_impl.h"
|
#include "fsengine_impl.h"
|
||||||
|
|
||||||
#include "diriterator.h"
|
#include "diriterator.h"
|
||||||
|
#include "expected.h"
|
||||||
#include "filepathinfocache.h"
|
#include "filepathinfocache.h"
|
||||||
|
|
||||||
#include "../filepath.h"
|
#include "../filepath.h"
|
||||||
@@ -62,8 +63,11 @@ bool FSEngineImpl::open(QIODevice::OpenMode openMode)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (read || append) {
|
if (read || append) {
|
||||||
const std::optional<QByteArray> contents = m_filePath.fileContents();
|
const expected_str<QByteArray> readResult = m_filePath.fileContents();
|
||||||
QTC_ASSERT(contents && m_tempStorage->write(*contents) >= 0, return false);
|
QTC_ASSERT_EXPECTED(readResult, return false);
|
||||||
|
|
||||||
|
const expected_str<qint64> writeResult = m_tempStorage->write(*readResult);
|
||||||
|
QTC_ASSERT_EXPECTED(writeResult, return false);
|
||||||
|
|
||||||
if (!append)
|
if (!append)
|
||||||
m_tempStorage->seek(0);
|
m_tempStorage->seek(0);
|
||||||
@@ -133,7 +137,9 @@ bool FSEngineImpl::remove()
|
|||||||
|
|
||||||
bool FSEngineImpl::copy(const QString &newName)
|
bool FSEngineImpl::copy(const QString &newName)
|
||||||
{
|
{
|
||||||
return m_filePath.copyFile(FilePath::fromString(newName));
|
expected_str<void> result = m_filePath.copyFile(FilePath::fromString(newName));
|
||||||
|
QTC_ASSERT_EXPECTED(result, return false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FSEngineImpl::rename(const QString &newName)
|
bool FSEngineImpl::rename(const QString &newName)
|
||||||
|
@@ -680,7 +680,9 @@ static bool copyFileIfNewer(const FilePath &sourceFilePath,
|
|||||||
|
|
||||||
if (!destinationFilePath.parentDir().ensureWritableDir())
|
if (!destinationFilePath.parentDir().ensureWritableDir())
|
||||||
return false;
|
return false;
|
||||||
return sourceFilePath.copyFile(destinationFilePath);
|
expected_str<void> result = sourceFilePath.copyFile(destinationFilePath);
|
||||||
|
QTC_ASSERT_EXPECTED(result, return false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidBuildApkStep::doRun()
|
void AndroidBuildApkStep::doRun()
|
||||||
|
@@ -75,7 +75,7 @@ static QJsonDocument readJsonFile(const FilePath &filePath)
|
|||||||
qCDebug(cmakeFileApi) << "readJsonFile:" << filePath;
|
qCDebug(cmakeFileApi) << "readJsonFile:" << filePath;
|
||||||
QTC_ASSERT(!filePath.isEmpty(), return {});
|
QTC_ASSERT(!filePath.isEmpty(), return {});
|
||||||
|
|
||||||
const std::optional<QByteArray> contents = filePath.fileContents();
|
const expected_str<QByteArray> contents = filePath.fileContents();
|
||||||
if (!contents)
|
if (!contents)
|
||||||
return {};
|
return {};
|
||||||
const QJsonDocument doc = QJsonDocument::fromJson(*contents);
|
const QJsonDocument doc = QJsonDocument::fromJson(*contents);
|
||||||
|
@@ -2,10 +2,11 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "presetsparser.h"
|
#include "presetsparser.h"
|
||||||
#include "utils/algorithm.h"
|
|
||||||
|
|
||||||
#include "cmakeprojectmanagertr.h"
|
#include "cmakeprojectmanagertr.h"
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@@ -391,7 +392,7 @@ const PresetsData &PresetsParser::presetsData() const
|
|||||||
|
|
||||||
bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage, int &errorLine)
|
bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage, int &errorLine)
|
||||||
{
|
{
|
||||||
const std::optional<QByteArray> jsonContents = jsonFile.fileContents();
|
const Utils::expected_str<QByteArray> jsonContents = jsonFile.fileContents();
|
||||||
if (!jsonContents) {
|
if (!jsonContents) {
|
||||||
errorMessage = Tr::tr("Failed to read %1 file").arg(jsonFile.fileName());
|
errorMessage = Tr::tr("Failed to read %1 file").arg(jsonFile.fileName());
|
||||||
return false;
|
return false;
|
||||||
|
@@ -652,7 +652,7 @@ void LoggingViewManagerWidget::loadAndUpdateFromPreset()
|
|||||||
if (fp.isEmpty())
|
if (fp.isEmpty())
|
||||||
return;
|
return;
|
||||||
// read file, update categories
|
// read file, update categories
|
||||||
const std::optional<QByteArray> contents = fp.fileContents();
|
const Utils::expected_str<QByteArray> contents = fp.fileContents();
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
QMessageBox::critical(ICore::dialogParent(),
|
QMessageBox::critical(ICore::dialogParent(),
|
||||||
tr("Error"),
|
tr("Error"),
|
||||||
|
@@ -136,9 +136,8 @@ bool CppToolsJsExtension::hasQObjectParent(const QString &klassName) const
|
|||||||
const WorkingCopy workingCopy = CppModelManager::instance()->workingCopy();
|
const WorkingCopy workingCopy = CppModelManager::instance()->workingCopy();
|
||||||
QByteArray source = workingCopy.source(item->filePath());
|
QByteArray source = workingCopy.source(item->filePath());
|
||||||
if (source.isEmpty()) {
|
if (source.isEmpty()) {
|
||||||
std::optional<QByteArray> contents = item->filePath().fileContents();
|
const Utils::expected_str<QByteArray> contents = item->filePath().fileContents();
|
||||||
if (!contents)
|
QTC_ASSERT_EXPECTED(contents, return false);
|
||||||
return false;
|
|
||||||
source = *contents;
|
source = *contents;
|
||||||
}
|
}
|
||||||
const auto doc = snapshot.preprocessedDocument(source, item->filePath());
|
const auto doc = snapshot.preprocessedDocument(source, item->filePath());
|
||||||
|
@@ -15,12 +15,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <utils/processhandle.h>
|
#include <utils/processhandle.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
#define QTC_ASSERT_STRINGIFY_HELPER(x) #x
|
|
||||||
#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x)
|
|
||||||
#define QTC_ASSERT_STRING(cond) qDebug("SOFT ASSERT: \"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__))
|
|
||||||
#define QTC_ASSERT(cond, action) if (cond) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
|
|
||||||
#define QTC_CHECK(cond) if (cond) {} else { QTC_ASSERT_STRING(#cond); } do {} while (0)
|
|
||||||
|
|
||||||
namespace Debugger::Internal {
|
namespace Debugger::Internal {
|
||||||
|
|
||||||
|
@@ -129,7 +129,7 @@ static QList<GitLabServer> readTokensFile(const Utils::FilePath &filePath)
|
|||||||
{
|
{
|
||||||
if (!filePath.exists())
|
if (!filePath.exists())
|
||||||
return {};
|
return {};
|
||||||
std::optional<QByteArray> contents = filePath.fileContents();
|
const Utils::expected_str<QByteArray> contents = filePath.fileContents();
|
||||||
if (!contents)
|
if (!contents)
|
||||||
return {};
|
return {};
|
||||||
const QByteArray content = *contents;
|
const QByteArray content = *contents;
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include <texteditor/texteditorconstants.h>
|
#include <texteditor/texteditorconstants.h>
|
||||||
#include <texteditor/fontsettings.h>
|
#include <texteditor/fontsettings.h>
|
||||||
|
|
||||||
|
#include <utils/expected.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
@@ -98,7 +99,9 @@ ExtraCompiler::ExtraCompiler(const Project *project, const FilePath &source,
|
|||||||
if (!d->compileTime.isValid() || d->compileTime > lastModified)
|
if (!d->compileTime.isValid() || d->compileTime > lastModified)
|
||||||
d->compileTime = lastModified;
|
d->compileTime = lastModified;
|
||||||
|
|
||||||
if (const std::optional<QByteArray> contents = target.fileContents())
|
const expected_str<QByteArray> contents = target.fileContents();
|
||||||
|
QTC_ASSERT_EXPECTED(contents, return);
|
||||||
|
|
||||||
setContent(target, *contents);
|
setContent(target, *contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,11 +172,12 @@ void ExtraCompiler::onTargetsBuilt(Project *project)
|
|||||||
if (d->compileTime >= generateTime)
|
if (d->compileTime >= generateTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (const std::optional<QByteArray> contents = target.fileContents()) {
|
const expected_str<QByteArray> contents = target.fileContents();
|
||||||
|
QTC_ASSERT_EXPECTED(contents, return);
|
||||||
|
|
||||||
d->compileTime = generateTime;
|
d->compileTime = generateTime;
|
||||||
setContent(target, *contents);
|
setContent(target, *contents);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -224,7 +224,7 @@ void ContentLibraryBundleImporter::handleImportTimer()
|
|||||||
QVariantHash ContentLibraryBundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath)
|
QVariantHash ContentLibraryBundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath)
|
||||||
{
|
{
|
||||||
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
|
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
|
||||||
const std::optional<QByteArray> content = assetRefPath.fileContents();
|
const Utils::expected_str<QByteArray> content = assetRefPath.fileContents();
|
||||||
if (content) {
|
if (content) {
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument bundleDataJsonDoc = QJsonDocument::fromJson(*content, &error);
|
QJsonDocument bundleDataJsonDoc = QJsonDocument::fromJson(*content, &error);
|
||||||
@@ -266,7 +266,7 @@ QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile)
|
|||||||
removedFiles.append(qmlFile);
|
removedFiles.append(qmlFile);
|
||||||
|
|
||||||
FilePath qmldirPath = bundleImportPath.resolvePath(QStringLiteral("qmldir"));
|
FilePath qmldirPath = bundleImportPath.resolvePath(QStringLiteral("qmldir"));
|
||||||
const std::optional<QByteArray> qmldirContent = qmldirPath.fileContents();
|
const expected_str<QByteArray> qmldirContent = qmldirPath.fileContents();
|
||||||
QByteArray newContent;
|
QByteArray newContent;
|
||||||
|
|
||||||
QString qmlType = qmlFilePath.baseName();
|
QString qmlType = qmlFilePath.baseName();
|
||||||
|
@@ -144,7 +144,9 @@ bool ScriptHelper::writeScriptFile(const Utils::FilePath &outScriptFile,
|
|||||||
for (const QByteArray &line : functionFooter(m_language))
|
for (const QByteArray &line : functionFooter(m_language))
|
||||||
data.append(line).append('\n');
|
data.append(line).append('\n');
|
||||||
|
|
||||||
return outScriptFile.writeFileContents(data);
|
const Utils::expected_str<qint64> result = outScriptFile.writeFileContents(data);
|
||||||
|
QTC_ASSERT_EXPECTED(result, return false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -179,8 +179,8 @@ static bool copyScriptTemplates(const SuiteConf &suiteConf, const Utils::FilePat
|
|||||||
const Utils::FilePath test = scripts.pathAppended(testStr + extension);
|
const Utils::FilePath test = scripts.pathAppended(testStr + extension);
|
||||||
const Utils::FilePath testFile = destination.pathAppended("test" + extension);
|
const Utils::FilePath testFile = destination.pathAppended("test" + extension);
|
||||||
QTC_ASSERT(!testFile.exists(), return false);
|
QTC_ASSERT(!testFile.exists(), return false);
|
||||||
ok = test.copyFile(testFile);
|
const Utils::expected_str<void> result = test.copyFile(testFile);
|
||||||
QTC_ASSERT(ok, return false);
|
QTC_ASSERT_EXPECTED(result, return false)
|
||||||
|
|
||||||
if (scripted)
|
if (scripted)
|
||||||
ok = suiteConf.ensureObjectMapExists();
|
ok = suiteConf.ensureObjectMapExists();
|
||||||
|
@@ -80,7 +80,7 @@ static QMap<QString, QString> readSuiteConfContent(const Utils::FilePath &file)
|
|||||||
if (!file.isReadableFile())
|
if (!file.isReadableFile())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::optional<QByteArray> suiteConfContent = file.fileContents();
|
const Utils::expected_str<QByteArray> suiteConfContent = file.fileContents();
|
||||||
if (!suiteConfContent)
|
if (!suiteConfContent)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@@ -112,7 +112,9 @@ static bool writeSuiteConfContent(const Utils::FilePath &file, const QMap<QStrin
|
|||||||
else
|
else
|
||||||
outData.append(it.key().toUtf8()).append('=').append(it.value().toUtf8()).append('\n');
|
outData.append(it.key().toUtf8()).append('=').append(it.value().toUtf8()).append('\n');
|
||||||
}
|
}
|
||||||
return file.writeFileContents(outData);
|
const Utils::expected_str<qint64> result = file.writeFileContents(outData);
|
||||||
|
QTC_ASSERT_EXPECTED(result, return false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SuiteConf::read()
|
bool SuiteConf::read()
|
||||||
@@ -306,9 +308,9 @@ bool SuiteConf::ensureObjectMapExists() const
|
|||||||
const Utils::FilePath objectMap = scripts.pathAppended("objectmap_template" + extension);
|
const Utils::FilePath objectMap = scripts.pathAppended("objectmap_template" + extension);
|
||||||
bool ok = destinationObjectMap.parentDir().ensureWritableDir();
|
bool ok = destinationObjectMap.parentDir().ensureWritableDir();
|
||||||
QTC_ASSERT(ok, return false);
|
QTC_ASSERT(ok, return false);
|
||||||
ok = objectMap.copyFile(destinationObjectMap);
|
const Utils::expected_str<void> result = objectMap.copyFile(destinationObjectMap);
|
||||||
QTC_ASSERT(ok, return false);
|
QTC_ASSERT_EXPECTED(result, return false);
|
||||||
return ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -256,9 +256,8 @@ void CallgrindToolRunner::triggerParse()
|
|||||||
m_hostOutputFile = FilePath::fromString(dataFile.fileName());
|
m_hostOutputFile = FilePath::fromString(dataFile.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto afterCopy = [this](bool res) {
|
const auto afterCopy = [this](expected_str<void> res) {
|
||||||
QTC_CHECK(res);
|
QTC_ASSERT_EXPECTED(res, return);
|
||||||
QTC_ASSERT(m_hostOutputFile.exists(), return);
|
|
||||||
showStatusMessage(Tr::tr("Parsing Profile Data..."));
|
showStatusMessage(Tr::tr("Parsing Profile Data..."));
|
||||||
m_parser.parse(m_hostOutputFile);
|
m_parser.parse(m_hostOutputFile);
|
||||||
};
|
};
|
||||||
|
@@ -2,6 +2,7 @@ add_subdirectory(ansiescapecodehandler)
|
|||||||
add_subdirectory(asynctask)
|
add_subdirectory(asynctask)
|
||||||
add_subdirectory(commandline)
|
add_subdirectory(commandline)
|
||||||
add_subdirectory(deviceshell)
|
add_subdirectory(deviceshell)
|
||||||
|
add_subdirectory(expected)
|
||||||
add_subdirectory(fileutils)
|
add_subdirectory(fileutils)
|
||||||
add_subdirectory(fsengine)
|
add_subdirectory(fsengine)
|
||||||
add_subdirectory(fuzzymatcher)
|
add_subdirectory(fuzzymatcher)
|
||||||
|
4
tests/auto/utils/expected/CMakeLists.txt
Normal file
4
tests/auto/utils/expected/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
add_qtc_test(tst_utils_expected
|
||||||
|
DEPENDS Utils
|
||||||
|
SOURCES tst_expected.cpp
|
||||||
|
)
|
7
tests/auto/utils/expected/expected.qbs
Normal file
7
tests/auto/utils/expected/expected.qbs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import qbs
|
||||||
|
|
||||||
|
QtcAutotest {
|
||||||
|
name: "Expected autotest"
|
||||||
|
Depends { name: "Utils" }
|
||||||
|
files: "tst_expected.cpp"
|
||||||
|
}
|
38
tests/auto/utils/expected/tst_expected.cpp
Normal file
38
tests/auto/utils/expected/tst_expected.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include <QtTest/qtestcase.h>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <utils/expected.h>
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
class tst_expected : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void initTestCase() {}
|
||||||
|
|
||||||
|
void tryMonads()
|
||||||
|
{
|
||||||
|
FilePath p = "idontexists.ne";
|
||||||
|
|
||||||
|
auto result = p.fileContents()
|
||||||
|
.and_then([](auto) { return expected_str<QByteArray>{}; })
|
||||||
|
.or_else([](auto error) {
|
||||||
|
return expected_str<QByteArray>(
|
||||||
|
make_unexpected(QString("Error: " + error)));
|
||||||
|
})
|
||||||
|
.transform_or([](auto error) -> QString {
|
||||||
|
return QString(QString("More Info: ") + error);
|
||||||
|
});
|
||||||
|
|
||||||
|
QVERIFY(!result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
QTEST_GUILESS_MAIN(tst_expected)
|
||||||
|
|
||||||
|
#include "tst_expected.moc"
|
@@ -1,9 +1,9 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include <QtTest>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
@@ -18,7 +18,7 @@ namespace QTest {
|
|||||||
{
|
{
|
||||||
return qstrdup(filePath.toString().toLocal8Bit().constData());
|
return qstrdup(filePath.toString().toLocal8Bit().constData());
|
||||||
}
|
}
|
||||||
}
|
} // namespace QTest
|
||||||
|
|
||||||
class tst_fileutils : public QObject
|
class tst_fileutils : public QObject
|
||||||
{
|
{
|
||||||
@@ -1027,7 +1027,7 @@ void tst_fileutils::asyncLocalCopy()
|
|||||||
const FilePath orig = FilePath::fromString(rootPath).pathAppended("x/y/fileToCopy.txt");
|
const FilePath orig = FilePath::fromString(rootPath).pathAppended("x/y/fileToCopy.txt");
|
||||||
QVERIFY(orig.exists());
|
QVERIFY(orig.exists());
|
||||||
const FilePath dest = FilePath::fromString(rootPath).pathAppended("x/fileToCopyDest.txt");
|
const FilePath dest = FilePath::fromString(rootPath).pathAppended("x/fileToCopyDest.txt");
|
||||||
auto afterCopy = [&orig, &dest, this] (bool result) {
|
auto afterCopy = [&orig, &dest, this](expected_str<void> result) {
|
||||||
QVERIFY(result);
|
QVERIFY(result);
|
||||||
// check existence, size and content
|
// check existence, size and content
|
||||||
QVERIFY(dest.exists());
|
QVERIFY(dest.exists());
|
||||||
|
@@ -7,6 +7,7 @@ Project {
|
|||||||
"asynctask/asynctask.qbs",
|
"asynctask/asynctask.qbs",
|
||||||
"commandline/commandline.qbs",
|
"commandline/commandline.qbs",
|
||||||
"deviceshell/deviceshell.qbs",
|
"deviceshell/deviceshell.qbs",
|
||||||
|
"expected/expected.qbs",
|
||||||
"fileutils/fileutils.qbs",
|
"fileutils/fileutils.qbs",
|
||||||
"fsengine/fsengine.qbs",
|
"fsengine/fsengine.qbs",
|
||||||
"fuzzymatcher/fuzzymatcher.qbs",
|
"fuzzymatcher/fuzzymatcher.qbs",
|
||||||
|
Reference in New Issue
Block a user