Mercurial > hg > vamp-plugin-pack
comparison installer.cpp @ 97:b5230bda1f1f
The RDF versions are too unreliable, nobody ever remembers to update them. Pull the bundled versions from the actual bundled libraries instead
author | Chris Cannam |
---|---|
date | Fri, 28 Feb 2020 10:41:54 +0000 |
parents | 24d64a983fc8 |
children | fb4ca43863b5 |
comparison
equal
deleted
inserted
replaced
96:e7badb8450d8 | 97:b5230bda1f1f |
---|---|
143 QString title; | 143 QString title; |
144 QString maker; | 144 QString maker; |
145 QString description; | 145 QString description; |
146 QString page; | 146 QString page; |
147 QStringList pluginTitles; | 147 QStringList pluginTitles; |
148 map<QString, int> pluginVersions; // id -> version | |
149 QString licence; | 148 QString licence; |
150 }; | 149 }; |
151 | 150 |
152 QString | 151 QString |
153 identifyLicence(QString libraryBasename) | 152 identifyLicence(QString libraryBasename) |
282 store.expand("dc:title"), | 281 store.expand("dc:title"), |
283 Node())); | 282 Node())); |
284 if (ptitle.type == Node::Literal) { | 283 if (ptitle.type == Node::Literal) { |
285 info.pluginTitles.push_back(ptitle.value); | 284 info.pluginTitles.push_back(ptitle.value); |
286 } | 285 } |
287 | |
288 Node pident = store.complete(Triple(p.object(), | |
289 store.expand("vamp:identifier"), | |
290 Node())); | |
291 Node pversion = store.complete(Triple(p.object(), | |
292 store.expand("owl:versionInfo"), | |
293 Node())); | |
294 if (pident.type == Node::Literal && | |
295 pversion.type == Node::Literal) { | |
296 bool ok = false; | |
297 int version = pversion.value.toInt(&ok); | |
298 if (ok) { | |
299 info.pluginVersions[pident.value] = version; | |
300 } | |
301 } | |
302 } | 286 } |
303 | 287 |
304 info.licence = identifyLicence(libId.value); | 288 info.licence = identifyLicence(libId.value); |
305 SVCERR << "licence = " << info.licence << endl; | 289 SVCERR << "licence = " << info.licence << endl; |
306 | 290 |
322 QFile(tempFile).remove(); | 306 QFile(tempFile).remove(); |
323 } | 307 } |
324 } | 308 } |
325 QString tempFile; | 309 QString tempFile; |
326 }; | 310 }; |
311 | |
312 bool | |
313 unbundleFile(QString filePath, QString targetPath, bool isExecutable) | |
314 { | |
315 SVCERR << "Copying " << filePath.toStdString() << " to " | |
316 << targetPath.toStdString() << "..." << endl; | |
317 | |
318 // This has to be able to work even if the destination exists, and | |
319 // to do so without deleting it first - e.g. when copying to a | |
320 // temporary file. So we open the file and copy to it ourselves | |
321 // rather than use QFile::copy | |
322 | |
323 QFile source(filePath); | |
324 if (!source.open(QFile::ReadOnly)) { | |
325 SVCERR << "ERROR: Failed to read bundled file " << filePath << endl; | |
326 return {}; | |
327 } | |
328 QByteArray content = source.readAll(); | |
329 source.close(); | |
330 | |
331 QFile target(targetPath); | |
332 if (!target.open(QFile::WriteOnly)) { | |
333 SVCERR << "ERROR: Failed to read target file " << targetPath << endl; | |
334 return {}; | |
335 } | |
336 if (target.write(content) != content.size()) { | |
337 SVCERR << "ERROR: Incomplete write to target file" << endl; | |
338 return {}; | |
339 } | |
340 target.close(); | |
341 | |
342 auto permissions = | |
343 QFile::ReadOwner | QFile::WriteOwner | | |
344 QFile::ReadGroup | | |
345 QFile::ReadOther; | |
346 | |
347 if (isExecutable) { | |
348 permissions |= | |
349 QFile::ExeOwner | | |
350 QFile::ExeGroup | | |
351 QFile::ExeOther; | |
352 }; | |
353 | |
354 if (!QFile::setPermissions(targetPath, permissions)) { | |
355 SVCERR << "Failed to set permissions on " | |
356 << targetPath.toStdString() << endl; | |
357 return false; | |
358 } | |
359 | |
360 return true; | |
361 } | |
327 | 362 |
328 map<QString, int> | 363 map<QString, int> |
329 getLibraryPluginVersions(QString libraryFilePath) | 364 getLibraryPluginVersions(QString libraryFilePath) |
330 { | 365 { |
331 static QMutex mutex; | 366 static QMutex mutex; |
354 | 389 |
355 #ifdef Q_OS_WIN32 | 390 #ifdef Q_OS_WIN32 |
356 QString helperPath = ":out/get-version.exe"; | 391 QString helperPath = ":out/get-version.exe"; |
357 #else | 392 #else |
358 QString helperPath = ":out/get-version"; | 393 QString helperPath = ":out/get-version"; |
359 #endif | 394 #endif |
360 QFile helper(helperPath); | 395 |
361 if (!helper.open(QFile::ReadOnly)) { | 396 tempFile.close(); |
362 SVCERR << "ERROR: Failed to read helper code" << endl; | 397 if (!unbundleFile(helperPath, tempFileName, true)) { |
398 SVCERR << "ERROR: Failed to unbundle helper code" << endl; | |
363 return {}; | 399 return {}; |
364 } | 400 } |
365 QByteArray content = helper.readAll(); | 401 |
366 helper.close(); | |
367 | |
368 if (tempFile.write(content) != content.size()) { | |
369 SVCERR << "ERROR: Incomplete write to temporary file" << endl; | |
370 return {}; | |
371 } | |
372 tempFile.close(); | |
373 | |
374 if (!QFile::setPermissions | |
375 (tempFileName, | |
376 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner)) { | |
377 SVCERR << "ERROR: Failed to set execute permission on helper " | |
378 << tempFileName << endl; | |
379 return {}; | |
380 } | |
381 | |
382 initSucceeded = true; | 402 initSucceeded = true; |
383 } | 403 } |
384 | 404 |
385 if (!initSucceeded) { | 405 if (!initSucceeded) { |
386 return {}; | 406 return {}; |
431 } | 451 } |
432 versions[parts[0]] = version; | 452 versions[parts[0]] = version; |
433 } | 453 } |
434 | 454 |
435 return versions; | 455 return versions; |
456 } | |
457 | |
458 map<QString, int> | |
459 getBundledLibraryPluginVersions(QString libraryFileName) | |
460 { | |
461 QString tempFileName; | |
462 TempFileDeleter deleter; | |
463 | |
464 { | |
465 QTemporaryFile tempFile; | |
466 tempFile.setAutoRemove(false); | |
467 if (!tempFile.open()) { | |
468 SVCERR << "ERROR: Failed to open a temporary file" << endl; | |
469 return {}; | |
470 } | |
471 | |
472 // We can't use QTemporaryFile's auto-remove, as it will hold | |
473 // the file open and that prevents us from executing it. Hence | |
474 // the separate deleter. | |
475 | |
476 tempFileName = tempFile.fileName(); | |
477 deleter.tempFile = tempFileName; | |
478 tempFile.close(); | |
479 } | |
480 | |
481 if (!unbundleFile(":out/" + libraryFileName, tempFileName, true)) { | |
482 return {}; | |
483 } | |
484 | |
485 return getLibraryPluginVersions(tempFileName); | |
436 } | 486 } |
437 | 487 |
438 bool isLibraryNewer(map<QString, int> a, map<QString, int> b) | 488 bool isLibraryNewer(map<QString, int> a, map<QString, int> b) |
439 { | 489 { |
440 // a and b are maps from plugin id to plugin version for libraries | 490 // a and b are maps from plugin id to plugin version for libraries |
520 RelativeStatus | 570 RelativeStatus |
521 getRelativeStatus(LibraryInfo info, QString targetDir) | 571 getRelativeStatus(LibraryInfo info, QString targetDir) |
522 { | 572 { |
523 QString destination = targetDir + "/" + info.fileName; | 573 QString destination = targetDir + "/" + info.fileName; |
524 | 574 |
525 RelativeStatus status = RelativeStatus::New; | |
526 | |
527 SVCERR << "\ngetRelativeStatus: " << info.fileName << ":\n"; | 575 SVCERR << "\ngetRelativeStatus: " << info.fileName << ":\n"; |
528 | 576 |
529 if (QFileInfo(destination).exists()) { | 577 if (!QFileInfo(destination).exists()) { |
530 | 578 SVCERR << " - relative status: " << relativeStatusLabel(RelativeStatus::New) << endl; |
531 auto installed = getLibraryPluginVersions(destination); | 579 return RelativeStatus::New; |
532 | 580 } |
533 SVCERR << " * installed: " << versionsString(installed) | 581 |
534 << "\n * packaged: " << versionsString(info.pluginVersions) | 582 RelativeStatus status = RelativeStatus::Same; |
535 << endl; | 583 |
536 | 584 auto packaged = getBundledLibraryPluginVersions(info.fileName); |
537 status = RelativeStatus::Same; | 585 auto installed = getLibraryPluginVersions(destination); |
538 | 586 |
539 if (installed.empty()) { | 587 SVCERR << " * installed: " << versionsString(installed) |
540 status = RelativeStatus::TargetNotLoadable; | 588 << "\n * packaged: " << versionsString(packaged) |
541 } | 589 << endl; |
542 | 590 |
543 if (isLibraryNewer(installed, info.pluginVersions)) { | 591 if (installed.empty()) { |
544 status = RelativeStatus::Downgrade; | 592 status = RelativeStatus::TargetNotLoadable; |
545 } | 593 } |
546 | 594 |
547 if (isLibraryNewer(info.pluginVersions, installed)) { | 595 if (isLibraryNewer(installed, packaged)) { |
548 status = RelativeStatus::Upgrade; | 596 status = RelativeStatus::Downgrade; |
549 } | 597 } |
598 | |
599 if (isLibraryNewer(packaged, installed)) { | |
600 status = RelativeStatus::Upgrade; | |
550 } | 601 } |
551 | 602 |
552 SVCERR << " - relative status: " << relativeStatusLabel(status) << endl; | 603 SVCERR << " - relative status: " << relativeStatusLabel(status) << endl; |
553 | 604 |
554 return status; | 605 return status; |
582 QString | 633 QString |
583 installLibrary(LibraryInfo info, QString targetDir) | 634 installLibrary(LibraryInfo info, QString targetDir) |
584 { | 635 { |
585 QString library = info.fileName; | 636 QString library = info.fileName; |
586 QString source = ":out"; | 637 QString source = ":out"; |
587 QFile f(source + "/" + library); | |
588 QString destination = targetDir + "/" + library; | 638 QString destination = targetDir + "/" + library; |
589 | 639 |
590 static QString backupDirName; | 640 static QString backupDirName; |
591 if (backupDirName == "") { | 641 if (backupDirName == "") { |
592 // Static so as to be created once - don't go creating a | 642 // Static so as to be created once - don't go creating a |
603 } | 653 } |
604 | 654 |
605 if (!backup(destination, backupDir)) { | 655 if (!backup(destination, backupDir)) { |
606 return QObject::tr("Failed to move aside existing library"); | 656 return QObject::tr("Failed to move aside existing library"); |
607 } | 657 } |
608 | 658 |
609 SVCERR << "Copying " << library.toStdString() << " to " | 659 if (!unbundleFile(source + "/" + library, destination, true)) { |
610 << destination.toStdString() << "..." << endl; | 660 return QObject::tr("Failed to copy library file to target directory"); |
611 if (!f.copy(destination)) { | 661 } |
612 SVCERR << "Failed to copy " << library.toStdString() | 662 |
613 << " to target " << destination.toStdString() << endl; | |
614 return QObject::tr("Failed to copy library to destination directory"); | |
615 } | |
616 if (!QFile::setPermissions | |
617 (destination, | |
618 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | | |
619 QFile::ReadGroup | QFile::ExeGroup | | |
620 QFile::ReadOther | QFile::ExeOther)) { | |
621 SVCERR << "Failed to set permissions on " | |
622 << library.toStdString() << endl; | |
623 return QObject::tr("Failed to set correct permissions on installed library"); | |
624 } | |
625 | |
626 QString base = QFileInfo(library).baseName(); | 663 QString base = QFileInfo(library).baseName(); |
627 QDir dir(source); | 664 QDir dir(source); |
628 auto entries = dir.entryList({ base + "*" }); | 665 auto entries = dir.entryList({ base + "*" }); |
629 for (auto e: entries) { | 666 for (auto e: entries) { |
630 if (e == library) continue; | 667 if (e == library) continue; |
631 QString destination = targetDir + "/" + e; | 668 QString destination = targetDir + "/" + e; |
632 if (!backup(destination, backupDir)) { | 669 if (!backup(destination, backupDir)) { |
633 continue; | 670 continue; |
634 } | 671 } |
635 SVCERR << "Copying " << e.toStdString() << " to " | 672 if (!unbundleFile(source + "/" + e, destination, false)) { |
636 << destination.toStdString() << "..." << endl; | |
637 if (!QFile(source + "/" + e).copy(destination)) { | |
638 SVCERR << "Failed to copy " << e.toStdString() | |
639 << " to target " << destination.toStdString() | |
640 << " (ignoring)" << endl; | |
641 continue; | |
642 } | |
643 if (!QFile::setPermissions | |
644 (destination, | |
645 QFile::ReadOwner | QFile::WriteOwner | | |
646 QFile::ReadGroup | | |
647 QFile::ReadOther)) { | |
648 SVCERR << "Failed to set permissions on " | |
649 << destination.toStdString() | |
650 << " (ignoring)" << endl; | |
651 continue; | 673 continue; |
652 } | 674 } |
653 } | 675 } |
654 | 676 |
655 return {}; | 677 return {}; |