Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldomfilewriter.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/qrandom.h>
7#include <QtCore/qscopeguard.h>
8#include <QtCore/qtextstream.h>
9
11namespace QQmlJS {
12namespace Dom {
13
14FileWriter::Status FileWriter::write(const QString &tFile, function_ref<bool(QTextStream &)> write,
15 int nBk)
16{
17 if (shouldRemoveTempFile)
18 tempFile.remove();
19 tempFile.close();
21 Q_ASSERT(status != Status::ShouldWrite);
22 status = Status::ShouldWrite;
23 targetFile = tFile;
24 newBkFiles.clear();
25 warnings.clear();
26
27 int i = 0;
28 const int maxAttempts = 20;
29 for (; i < maxAttempts; ++i) {
30 tempFile.setFileName(targetFile
31 + QString::number(QRandomGenerator::global()->generate(), 16).mid(0, 8)
32 + QStringLiteral(u".tmp"));
33 if (tempFile.open(QIODevice::ReadWrite | QIODevice::NewOnly))
34 break;
35 }
36 if (i == maxAttempts) {
37 warnings.append(tr("Could not create temp file for %1").arg(targetFile));
38 status = FileWriter::Status::SkippedDueToFailure;
39 return status;
40 }
42 bool success = false;
43 QTextStream inF(&tempFile);
44 QT_TRY
45 {
46 auto cleanup = qScopeGuard([this, &inF, &success, nBk] {
47 inF.flush();
48 tempFile.flush();
49 tempFile.close();
50 if (success) {
51 if (QFile::exists(targetFile)) {
52 // compareFiles
53 if (tempFile.open(QIODevice::ReadOnly)) {
54 auto closeTmpF = qScopeGuard([this] { tempFile.close(); });
55 QFile oldF(targetFile);
56 if (oldF.open(QIODevice::ReadOnly)) {
57 bool same = true;
58 while (!tempFile.atEnd() && !oldF.atEnd()) {
59 QByteArray l1 = tempFile.readLine();
60 QByteArray l2 = oldF.readLine();
61 if (l1 != l2)
62 same = false;
63 }
64 if (tempFile.atEnd() && oldF.atEnd() && same) {
65 tempFile.remove();
66 shouldRemoveTempFile = false;
67 status = Status::SkippedEqual;
68 return;
69 }
70 }
71 }
72 }
73 // move to target
74 int i = 0;
75 const int maxAttempts = 10;
76 for (; i < maxAttempts; ++i) {
77 if (QFile::exists(targetFile)) {
78 // make place for targetFile
79 QString bkFileName;
80 if (nBk < 1) {
81 QFile::remove(targetFile);
82 } else if (nBk == 1) {
83 QString bkFileName = targetFile + QStringLiteral(u"~");
84 QFile::remove(bkFileName);
85 QFile::rename(targetFile, bkFileName);
86 } else {
87 // f~ is the oldest, further backups at f1~ .. f<nBk>~
88 // keeping an empty place for the "next" backup
89 // f~ is never overwritten
90 int iBk = 0;
91 QString bkFileName = targetFile + QStringLiteral(u"~");
92 while (++iBk < nBk) {
93 if (QFile::exists(bkFileName))
94 bkFileName = targetFile + QString::number(iBk)
95 + QStringLiteral(u"~");
96 }
97 if (iBk == nBk)
98 QFile::remove(targetFile + QStringLiteral(u"1~"));
99 else
100 QFile::remove(targetFile + QString::number(++iBk)
101 + QStringLiteral(u"~"));
102 QFile::remove(bkFileName);
103 QFile::rename(targetFile, bkFileName);
104 }
105 if (!bkFileName.isEmpty() && QFile::rename(targetFile, bkFileName))
106 newBkFiles.append(bkFileName);
107 }
108 if (tempFile.rename(targetFile)) {
109 status = Status::DidWrite;
110 shouldRemoveTempFile = false;
111 return;
112 }
113 }
114 warnings.append(
115 tr("Rename of file %1 to %2 failed").arg(tempFile.fileName(), targetFile));
116 status = Status::SkippedDueToFailure;
117 } else {
118 warnings.append(tr("Error while writing"));
119 }
120 });
121 success = write(inF);
122 }
123 QT_CATCH(...)
124 {
125 warnings.append(tr("Exception trying to write file %1").arg(targetFile));
126 status = FileWriter::Status::SkippedDueToFailure;
127 }
128 if (status == Status::ShouldWrite)
129 status = Status::SkippedDueToFailure;
130 return status;
131}
132
133} // namespace Dom
134} // namespace QQmlJS
135QT_END_NAMESPACE
136
137#include "moc_qqmldomfilewriter_p.cpp"
Status write(const QString &targetFile, function_ref< bool(QTextStream &)> write, int nBk=2)