Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
4.1.0, 4.0.0, 4.1.1
-
Windows 10, QT IFW 4.1.1.
-
-
Qt Installer Sprint 37-Summer
Description
Can't update existing repository
Description
Updating an existing repository with repogen produce a 7zip unknown exception.
Could you please confirm if bug and solution found are correct.
Reproduce issue
Create repository with at least 2 components
> C:\Qt\QtIFW-4.1.1\bin\repogen.exe -p packages1 repository
Add updated or new components to repository
> C:\Qt\QtIFW-4.1.1\bin\repogen.exe -p packages2 -update repository
Caught 7zip exception: Unknown exception caught (void __cdecl Lib7z::createArchive(const class QString &,const class QStringList &,enum Lib7z::TmpFile,enum Lib7z::Compression,class Lib7z::UpdateCallback *))
Debug
Versions
Bug not present in 3.2.2, but in 4.0 and 4.1.
Was introduced after unifyMetadata functionality was created.
Going through call stack
installer-framework\src\libs\ifwtools\repositorygen.cpp
- QInstallerTools::createRepository
- QInstallerTools::compressMetaDirectories
- QInstallerTools::unifyMetadata
installer-framework\src\libs\installer\lib7z_facade.cpp
- Lib7z::createArchive
installer-framework\src\libs\7zip\win\CPP\7zip\UI\Common\Update.cpp
- UpdateArchive
- Compress
installer-framework\src\libs\7zip\win\CPP\7zip\UI\Common\UpdatePair.cpp
- GetUpdatePairInfoList
-> line 123. ThrowError k_Duplicate_inDir_Message
So it seems that the 7Zip unknown error correspond to duplicate filenames passed as arguments.
Source code
repositorygen.cpp, QInstallerTools::unifyMetadata, line 807, foreach loop.
Checking args passed through the functions, the bug seems to be on Qt ifw side.
When a unified zip containing metadata of previous and new packages is created.
For this test, we assume that package A, B and C are in temp dir, we cant to add packages D,E.
Before loop
A list containing the absolute paths of each component we want to add is created.
QStringList absPaths;
QDir dir(repoDir);
const QStringList entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);foreach (const QString &i, entryList) {
dir.cd;
const QString absPath = dir.absolutePath();
absPaths.append(absPath);
dir.cdUp();
}
Abspaths content :
("C:/Users/USERNAME/AppData/Local/Temp/repogen-LDfpzY/com.vendor.packageD",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-LDfpzY/com.vendor.packageE")
Then we check for packages already existing in repo, to add their path too.
//Checking if a repo exist already
QTemporaryDir existingRepoTempDir;
QString existingRepoTemp = existingRepoTempDir.path();if (!existingRepoDir.isEmpty()) {
existingRepoTempDir.setAutoRemove(false);
QFile archiveFile(existingRepoDir);
QInstaller::openForRead(&archiveFile);
Lib7z::extractArchive(&archiveFile, existingRepoTemp);
QDir dir2(existingRepoTemp);//Entrylist contains names of packages, such as com.vendor.product1, com.vendor.product2
QStringList existingRepoEntries = dir2.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QString existingRepoEntry, existingRepoEntries) {
if (entryList.contains(existingRepoEntry)) {
continue;
} else {
dir2.cd(existingRepoEntry);
const QString absPath = dir2.absolutePath();
absPaths.append(absPath);
}
}
}
After loop
Abspaths now contains path of previous and new components.
But there are duplicates.
("C:/Users/USERNAME/AppData/Local/Temp/repogen-LDfpzY/com.vendor.packageD",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-LDfpzY/com.vendor.packageE",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-mtFrRf/com.vendor.packageA",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-mtFrRf/com.vendor.packageA",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-mtFrRf/com.vendor.packageA")
Then the Lib7z::createArchive call that throw the exception because of duplicate filenames.
// Compress all metadata from repository to one single 7z
const QString metadataFilename = QDateTime::currentDateTime().
toString(QLatin1String("yyyy-MM-dd-hhmm")) + QLatin1String("_meta.7z");
const QString tmpTarget = repoDir QDir::separator() metadataFilename;Lib7z::createArchive(tmpTarget, absPaths, Lib7z::TmpFile::No);
Solution
The foreach > else part seems to be missing a dir.cdUp().
It cause the dir2.cd(...) to enter the first package directory, and search all the subsequent packages inside of it, and fail.
Then dir2.absolutePath() always return the path of the first package.
foreach (const QString existingRepoEntry, existingRepoEntries) {
if (entryList.contains(existingRepoEntry)) {
continue;
} else {
dir2.cd(existingRepoEntry);
const QString absPath = dir2.absolutePath();
absPaths.append(absPath);dir2.cdUp(); // ADDED
}
}
After fix, abspaths seems to be correct before entering createArchive function.
And 7Zip error doesn't appear again.
("C:/Users/USERNAME/AppData/Local/Temp/repogen-LDfpzY/com.vendor.packageD",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-LDfpzY/com.vendor.packageE",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-mtFrRf/com.vendor.packageA",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-mtFrRf/com.vendor.packageB",
"C:/Users/USERNAME/AppData/Local/Temp/repogen-mtFrRf/com.vendor.packageC")