package kit: Add pre-uninstall scripts feature.
Just like post-install scripts which run shortly after a package is installed, pre-uninstall scripts are run just before a package is removed. Implements enhancement #13427 * Fix script exit code handling vs script launch errors. * Bump package and repo file version numbers due to new attribute, unfortunately makes new .hpkg files not backwards compatible. * Add pre-uninstall functionality, mostly cloning the post-install except in a few places. * Discover that _RunQueuedScripts() is never called, a future TODO:? * Update package documentation for pre-uninstall scripts, and use of the boot/post-install directory. Change-Id: I45596255ce74bc102f6e5b606cbf83e4e4347a17 Reviewed-on: https://review.haiku-os.org/c/haiku/+/1504 Reviewed-by: Alexander G. M. Smith <[email protected]> Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
e6f60cad2a
commit
a22fa0c977
@@ -178,7 +178,11 @@ The supported attributes are:
|
|||||||
- ``groups``: A list of names of Unix groups the packaged software requires.
|
- ``groups``: A list of names of Unix groups the packaged software requires.
|
||||||
- ``post-install-scripts``: A list of paths of files included in the package,
|
- ``post-install-scripts``: A list of paths of files included in the package,
|
||||||
which shall be executed on package activation. Each path must start with
|
which shall be executed on package activation. Each path must start with
|
||||||
"boot/post-install/".
|
"boot/post-install/". All the files in that directory are also run on first
|
||||||
|
boot after installing or copying the OS to a new disk.
|
||||||
|
- ``pre-uninstall-scripts``: A list of paths of files included in the package,
|
||||||
|
which shall be executed on package deactivation. For consistency, each path
|
||||||
|
should start with "boot/pre-uninstall/".
|
||||||
|
|
||||||
Version Strings
|
Version Strings
|
||||||
---------------
|
---------------
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ total_size
|
|||||||
|
|
||||||
minor_version
|
minor_version
|
||||||
The minor version of the HPKG format the file conforms to. The current minor
|
The minor version of the HPKG format the file conforms to. The current minor
|
||||||
version is 0 (B_HPKG_MINOR_VERSION). Additions of new attributes to the
|
version is 1 (B_HPKG_MINOR_VERSION). Additions of new attributes to the
|
||||||
attributes or TOC sections should generally only increment the minor version.
|
attributes or TOC sections should generally only increment the minor version.
|
||||||
When a file with a greater minor version is encountered, the reader should
|
When a file with a greater minor version is encountered, the reader should
|
||||||
ignore unknown attributes.
|
ignore unknown attributes.
|
||||||
@@ -915,7 +915,18 @@ B_HPKG_ATTRIBUTE_ID_PACKAGE_POST_INSTALL_SCRIPT ("package:post-install-script")
|
|||||||
:Value: Relative path of a script that shall be executed after package
|
:Value: Relative path of a script that shall be executed after package
|
||||||
activation.
|
activation.
|
||||||
:Allowed Values: Installation location relative path of a file included in the
|
:Allowed Values: Installation location relative path of a file included in the
|
||||||
package.
|
package. Must start with "boot/post-install/", so besides being run after
|
||||||
|
package installation, it also gets run on the first boot after the OS is
|
||||||
|
installed.
|
||||||
|
:Child Attributes: none
|
||||||
|
|
||||||
|
B_HPKG_ATTRIBUTE_ID_PACKAGE_PRE_UNINSTALL_SCRIPT ("package:pre-uninstall-script")
|
||||||
|
:Type: string
|
||||||
|
:Value: Relative path of a script that shall be executed before package
|
||||||
|
deactivation.
|
||||||
|
:Allowed Values: Installation location relative path of a file included in
|
||||||
|
the package. For consistency, it is recommended to start with
|
||||||
|
"boot/pre-uninstall/".
|
||||||
:Child Attributes: none
|
:Child Attributes: none
|
||||||
|
|
||||||
Haiku Package Repository Format
|
Haiku Package Repository Format
|
||||||
@@ -994,8 +1005,8 @@ total_size
|
|||||||
|
|
||||||
minor_version
|
minor_version
|
||||||
The minor version of the HPKR format the file conforms to. The current minor
|
The minor version of the HPKR format the file conforms to. The current minor
|
||||||
version is 0 (B_HPKG_REPO_MINOR_VERSION). Additions of new attributes to the
|
version is 1 (B_HPKG_REPO_MINOR_VERSION). Additions of new attributes to the
|
||||||
attributes section shouldgenerally only increment the minor version. When a
|
attributes section should generally only increment the minor version. When a
|
||||||
file with a greater minor version is encountered, the reader should ignore
|
file with a greater minor version is encountered, the reader should ignore
|
||||||
unknown attributes.
|
unknown attributes.
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,14 @@ Post-Installation Scripts
|
|||||||
=========================
|
=========================
|
||||||
A package may include one or more post-installation scripts. The scripts are
|
A package may include one or more post-installation scripts. The scripts are
|
||||||
executed whenever the package is activated (for the first time, but also after
|
executed whenever the package is activated (for the first time, but also after
|
||||||
package updates). They shall be placed in "boot/post-install" and declared
|
package updates and first boot of a newly installed OS). They shall be placed
|
||||||
explicitly by the package (via POST_INSTALL_SCRIPTS in the build recipe). A
|
in "boot/post-install" and declared explicitly by the package (via
|
||||||
post-install script should be considered the last resort. It should only be
|
POST_INSTALL_SCRIPTS in the build recipe). A post-install script should be
|
||||||
used, if there's no reasonable alternative.
|
considered the last resort. It should only be used, if there's no reasonable
|
||||||
|
alternative. A typical use would be to create a desktop icon that the user
|
||||||
|
can move around or delete.
|
||||||
|
|
||||||
|
Pre-Uninstallation Scripts
|
||||||
|
=========================
|
||||||
|
These undo the effects of a post-installation script and usually are put
|
||||||
|
into "boot/pre-uninstall". A typical use is to remove desktop icons.
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ public:
|
|||||||
B_POST_INSTALL_SCRIPT_NOT_FOUND,
|
B_POST_INSTALL_SCRIPT_NOT_FOUND,
|
||||||
B_STARTING_POST_INSTALL_SCRIPT_FAILED,
|
B_STARTING_POST_INSTALL_SCRIPT_FAILED,
|
||||||
B_POST_INSTALL_SCRIPT_FAILED,
|
B_POST_INSTALL_SCRIPT_FAILED,
|
||||||
|
B_PRE_UNINSTALL_SCRIPT_NOT_FOUND,
|
||||||
|
B_STARTING_PRE_UNINSTALL_SCRIPT_FAILED,
|
||||||
|
B_PRE_UNINSTALL_SCRIPT_FAILED,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public:
|
|||||||
const BStringList& Groups() const;
|
const BStringList& Groups() const;
|
||||||
|
|
||||||
const BStringList& PostInstallScripts() const;
|
const BStringList& PostInstallScripts() const;
|
||||||
|
const BStringList& PreUninstallScripts() const;
|
||||||
|
|
||||||
const BObjectList<BPackageResolvable>& ProvidesList() const;
|
const BObjectList<BPackageResolvable>& ProvidesList() const;
|
||||||
const BObjectList<BPackageResolvableExpression>&
|
const BObjectList<BPackageResolvableExpression>&
|
||||||
@@ -159,6 +160,9 @@ public:
|
|||||||
void ClearPostInstallScripts();
|
void ClearPostInstallScripts();
|
||||||
status_t AddPostInstallScript(const BString& path);
|
status_t AddPostInstallScript(const BString& path);
|
||||||
|
|
||||||
|
void ClearPreUninstallScripts();
|
||||||
|
status_t AddPreUninstallScript(const BString& path);
|
||||||
|
|
||||||
void ClearProvidesList();
|
void ClearProvidesList();
|
||||||
status_t AddProvides(const BPackageResolvable& provides);
|
status_t AddProvides(const BPackageResolvable& provides);
|
||||||
|
|
||||||
@@ -297,6 +301,7 @@ private:
|
|||||||
BStringList fGroups;
|
BStringList fGroups;
|
||||||
|
|
||||||
BStringList fPostInstallScripts;
|
BStringList fPostInstallScripts;
|
||||||
|
BStringList fPreUninstallScripts;
|
||||||
|
|
||||||
ResolvableList fProvidesList;
|
ResolvableList fProvidesList;
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ enum BPackageInfoAttributeID {
|
|||||||
// list of (Unix) groups defined/needed
|
// list of (Unix) groups defined/needed
|
||||||
B_PACKAGE_INFO_POST_INSTALL_SCRIPTS,
|
B_PACKAGE_INFO_POST_INSTALL_SCRIPTS,
|
||||||
// list of scripts to be executed post-install
|
// list of scripts to be executed post-install
|
||||||
|
B_PACKAGE_INFO_PRE_UNINSTALL_SCRIPTS,
|
||||||
|
// list of scripts to be run before uninstalling
|
||||||
//
|
//
|
||||||
B_PACKAGE_INFO_ENUM_COUNT,
|
B_PACKAGE_INFO_ENUM_COUNT,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ namespace BHPKG {
|
|||||||
enum {
|
enum {
|
||||||
B_HPKG_MAGIC = 'hpkg',
|
B_HPKG_MAGIC = 'hpkg',
|
||||||
B_HPKG_VERSION = 2,
|
B_HPKG_VERSION = 2,
|
||||||
B_HPKG_MINOR_VERSION = 0,
|
B_HPKG_MINOR_VERSION = 1,
|
||||||
//
|
//
|
||||||
B_HPKG_REPO_MAGIC = 'hpkr',
|
B_HPKG_REPO_MAGIC = 'hpkr',
|
||||||
B_HPKG_REPO_VERSION = 2,
|
B_HPKG_REPO_VERSION = 2,
|
||||||
B_HPKG_REPO_MINOR_VERSION = 0
|
B_HPKG_REPO_MINOR_VERSION = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,3 +82,10 @@ B_DEFINE_HPKG_ATTRIBUTE(52, STRING, "package:post-install-script",
|
|||||||
B_DEFINE_HPKG_ATTRIBUTE(53, UINT, "package:is-writable-directory",
|
B_DEFINE_HPKG_ATTRIBUTE(53, UINT, "package:is-writable-directory",
|
||||||
PACKAGE_IS_WRITABLE_DIRECTORY)
|
PACKAGE_IS_WRITABLE_DIRECTORY)
|
||||||
B_DEFINE_HPKG_ATTRIBUTE(54, STRING, "package", PACKAGE)
|
B_DEFINE_HPKG_ATTRIBUTE(54, STRING, "package", PACKAGE)
|
||||||
|
B_DEFINE_HPKG_ATTRIBUTE(55, STRING, "package:pre-uninstall-script",
|
||||||
|
PACKAGE_PRE_UNINSTALL_SCRIPT)
|
||||||
|
// Note: add new entries at the end to avoid breaking index numbers, which are
|
||||||
|
// in previously built .hpkg files the build process downloads from elsewhere.
|
||||||
|
// Also remember to bump B_HPKG_MINOR_VERSION and B_HPKG_REPO_MINOR_VERSION.
|
||||||
|
// And yes, the build (on Haiku) runs packaging tools compiled using your code,
|
||||||
|
// which makes it extra fun to debug :-)
|
||||||
|
|||||||
@@ -96,9 +96,9 @@ public:
|
|||||||
for (int32 i = 0; i < count; i++)
|
for (int32 i = 0; i < count; i++)
|
||||||
PrintPostInstallScript(info.PostInstallScripts().StringAt(i));
|
PrintPostInstallScript(info.PostInstallScripts().StringAt(i));
|
||||||
|
|
||||||
count = info.PostInstallScripts().CountStrings();
|
count = info.PreUninstallScripts().CountStrings();
|
||||||
for (int32 i = 0; i < count; i++)
|
for (int32 i = 0; i < count; i++)
|
||||||
PrintPostInstallScript(info.PostInstallScripts().StringAt(i));
|
PrintPreUninstallScript(info.PreUninstallScripts().StringAt(i));
|
||||||
|
|
||||||
if (!info.InstallPath().IsEmpty())
|
if (!info.InstallPath().IsEmpty())
|
||||||
PrintInstallPath(info.InstallPath());
|
PrintInstallPath(info.InstallPath());
|
||||||
@@ -203,6 +203,10 @@ public:
|
|||||||
PrintPostInstallScript(value.string);
|
PrintPostInstallScript(value.string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case B_PACKAGE_INFO_PRE_UNINSTALL_SCRIPTS:
|
||||||
|
PrintPreUninstallScript(value.string);
|
||||||
|
break;
|
||||||
|
|
||||||
case B_PACKAGE_INFO_INSTALL_PATH:
|
case B_PACKAGE_INFO_INSTALL_PATH:
|
||||||
PrintInstallPath(value.string);
|
PrintInstallPath(value.string);
|
||||||
break;
|
break;
|
||||||
@@ -379,7 +383,12 @@ public:
|
|||||||
|
|
||||||
void PrintPostInstallScript(const char* script) const
|
void PrintPostInstallScript(const char* script) const
|
||||||
{
|
{
|
||||||
printf("\tpost install script: %s\n", script);
|
printf("\tpost-install script: %s\n", script);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintPreUninstallScript(const char* script) const
|
||||||
|
{
|
||||||
|
printf("\tpre-uninstall script: %s\n", script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintInstallPath(const char* path) const
|
void PrintInstallPath(const char* path) const
|
||||||
|
|||||||
@@ -162,6 +162,18 @@ BTransactionIssue::ToString() const
|
|||||||
messageTemplate = "The post-installation script "
|
messageTemplate = "The post-installation script "
|
||||||
" \"%path1%\" failed with exit code %exitCode%.";
|
" \"%path1%\" failed with exit code %exitCode%.";
|
||||||
break;
|
break;
|
||||||
|
case B_PRE_UNINSTALL_SCRIPT_NOT_FOUND:
|
||||||
|
messageTemplate = "Failed to find pre-uninstall script "
|
||||||
|
" \"%path1%\": %error%.";
|
||||||
|
break;
|
||||||
|
case B_STARTING_PRE_UNINSTALL_SCRIPT_FAILED:
|
||||||
|
messageTemplate = "Failed to run pre-uninstall script "
|
||||||
|
" \"%path1%\": %error%.";
|
||||||
|
break;
|
||||||
|
case B_PRE_UNINSTALL_SCRIPT_FAILED:
|
||||||
|
messageTemplate = "The pre-uninstall script "
|
||||||
|
" \"%path1%\" failed with exit code %exitCode%.";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BString message(messageTemplate);
|
BString message(messageTemplate);
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ const char* const BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
|
|||||||
"user-settings-files",
|
"user-settings-files",
|
||||||
"users",
|
"users",
|
||||||
"groups",
|
"groups",
|
||||||
"post-install-scripts"
|
"post-install-scripts",
|
||||||
|
"pre-uninstall-scripts"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@ BPackageInfo::BPackageInfo()
|
|||||||
fUsers(4, true),
|
fUsers(4, true),
|
||||||
fGroups(4),
|
fGroups(4),
|
||||||
fPostInstallScripts(4),
|
fPostInstallScripts(4),
|
||||||
|
fPreUninstallScripts(4),
|
||||||
fProvidesList(20, true),
|
fProvidesList(20, true),
|
||||||
fRequiresList(20, true),
|
fRequiresList(20, true),
|
||||||
fSupplementsList(20, true),
|
fSupplementsList(20, true),
|
||||||
@@ -204,6 +206,7 @@ BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
|
|||||||
fUsers(4, true),
|
fUsers(4, true),
|
||||||
fGroups(4),
|
fGroups(4),
|
||||||
fPostInstallScripts(4),
|
fPostInstallScripts(4),
|
||||||
|
fPreUninstallScripts(4),
|
||||||
fProvidesList(20, true),
|
fProvidesList(20, true),
|
||||||
fRequiresList(20, true),
|
fRequiresList(20, true),
|
||||||
fSupplementsList(20, true),
|
fSupplementsList(20, true),
|
||||||
@@ -237,6 +240,8 @@ BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
|
|||||||
&& (error = _ExtractStringList(archive, "groups", fGroups)) == B_OK
|
&& (error = _ExtractStringList(archive, "groups", fGroups)) == B_OK
|
||||||
&& (error = _ExtractStringList(archive, "post-install-scripts",
|
&& (error = _ExtractStringList(archive, "post-install-scripts",
|
||||||
fPostInstallScripts)) == B_OK
|
fPostInstallScripts)) == B_OK
|
||||||
|
&& (error = _ExtractStringList(archive, "pre-uninstall-scripts",
|
||||||
|
fPreUninstallScripts)) == B_OK
|
||||||
&& (error = _ExtractResolvables(archive, "provides", fProvidesList))
|
&& (error = _ExtractResolvables(archive, "provides", fProvidesList))
|
||||||
== B_OK
|
== B_OK
|
||||||
&& (error = _ExtractResolvableExpressions(archive, "requires",
|
&& (error = _ExtractResolvableExpressions(archive, "requires",
|
||||||
@@ -554,6 +559,13 @@ BPackageInfo::PostInstallScripts() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BStringList&
|
||||||
|
BPackageInfo::PreUninstallScripts() const
|
||||||
|
{
|
||||||
|
return fPreUninstallScripts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const BObjectList<BPackageResolvable>&
|
const BObjectList<BPackageResolvable>&
|
||||||
BPackageInfo::ProvidesList() const
|
BPackageInfo::ProvidesList() const
|
||||||
{
|
{
|
||||||
@@ -852,6 +864,13 @@ BPackageInfo::ClearPostInstallScripts()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BPackageInfo::ClearPreUninstallScripts()
|
||||||
|
{
|
||||||
|
fPreUninstallScripts.MakeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BPackageInfo::AddPostInstallScript(const BString& path)
|
BPackageInfo::AddPostInstallScript(const BString& path)
|
||||||
{
|
{
|
||||||
@@ -859,6 +878,13 @@ BPackageInfo::AddPostInstallScript(const BString& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPackageInfo::AddPreUninstallScript(const BString& path)
|
||||||
|
{
|
||||||
|
return fPreUninstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BPackageInfo::ClearProvidesList()
|
BPackageInfo::ClearProvidesList()
|
||||||
{
|
{
|
||||||
@@ -992,6 +1018,7 @@ BPackageInfo::Clear()
|
|||||||
fUsers.MakeEmpty();
|
fUsers.MakeEmpty();
|
||||||
fGroups.MakeEmpty();
|
fGroups.MakeEmpty();
|
||||||
fPostInstallScripts.MakeEmpty();
|
fPostInstallScripts.MakeEmpty();
|
||||||
|
fPreUninstallScripts.MakeEmpty();
|
||||||
fRequiresList.MakeEmpty();
|
fRequiresList.MakeEmpty();
|
||||||
fProvidesList.MakeEmpty();
|
fProvidesList.MakeEmpty();
|
||||||
fSupplementsList.MakeEmpty();
|
fSupplementsList.MakeEmpty();
|
||||||
@@ -1031,6 +1058,8 @@ BPackageInfo::Archive(BMessage* archive, bool deep) const
|
|||||||
|| (error = archive->AddStrings("groups", fGroups)) != B_OK
|
|| (error = archive->AddStrings("groups", fGroups)) != B_OK
|
||||||
|| (error = archive->AddStrings("post-install-scripts",
|
|| (error = archive->AddStrings("post-install-scripts",
|
||||||
fPostInstallScripts)) != B_OK
|
fPostInstallScripts)) != B_OK
|
||||||
|
|| (error = archive->AddStrings("pre-uninstall-scripts",
|
||||||
|
fPreUninstallScripts)) != B_OK
|
||||||
|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
|
|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
|
||||||
|| (error = _AddResolvableExpressions(archive, "requires",
|
|| (error = _AddResolvableExpressions(archive, "requires",
|
||||||
fRequiresList)) != B_OK
|
fRequiresList)) != B_OK
|
||||||
@@ -1080,6 +1109,7 @@ BPackageInfo::GetConfigString(BString& _string) const
|
|||||||
.Write("users", fUsers)
|
.Write("users", fUsers)
|
||||||
.Write("groups", fGroups)
|
.Write("groups", fGroups)
|
||||||
.Write("post-install-scripts", fPostInstallScripts)
|
.Write("post-install-scripts", fPostInstallScripts)
|
||||||
|
.Write("pre-uninstall-scripts", fPreUninstallScripts)
|
||||||
.Write("provides", fProvidesList)
|
.Write("provides", fProvidesList)
|
||||||
.BeginRequires(fBasePackage)
|
.BeginRequires(fBasePackage)
|
||||||
.Write("requires", fRequiresList)
|
.Write("requires", fRequiresList)
|
||||||
|
|||||||
@@ -149,6 +149,10 @@ BPackageInfoContentHandler::HandlePackageAttribute(
|
|||||||
case B_PACKAGE_INFO_POST_INSTALL_SCRIPTS:
|
case B_PACKAGE_INFO_POST_INSTALL_SCRIPTS:
|
||||||
return fPackageInfo.AddPostInstallScript(value.string);
|
return fPackageInfo.AddPostInstallScript(value.string);
|
||||||
|
|
||||||
|
case B_PACKAGE_INFO_PRE_UNINSTALL_SCRIPTS:
|
||||||
|
fPackageInfo.AddPreUninstallScript(value.string);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (fErrorOutput != NULL) {
|
if (fErrorOutput != NULL) {
|
||||||
fErrorOutput->PrintError(
|
fErrorOutput->PrintError(
|
||||||
|
|||||||
@@ -1054,6 +1054,10 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
|
|||||||
_ParseStringList(&packageInfo->fPostInstallScripts);
|
_ParseStringList(&packageInfo->fPostInstallScripts);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case B_PACKAGE_INFO_PRE_UNINSTALL_SCRIPTS:
|
||||||
|
_ParseStringList(&packageInfo->fPreUninstallScripts);
|
||||||
|
break;
|
||||||
|
|
||||||
case B_PACKAGE_INFO_PROVIDES:
|
case B_PACKAGE_INFO_PROVIDES:
|
||||||
_ParseResolvableList(&packageInfo->fProvidesList);
|
_ParseResolvableList(&packageInfo->fProvidesList);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -668,6 +668,11 @@ ReaderImplBase::PackageAttributeHandler::HandleAttribute(
|
|||||||
value.string);
|
value.string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case B_HPKG_ATTRIBUTE_ID_PACKAGE_PRE_UNINSTALL_SCRIPT:
|
||||||
|
fPackageInfoValue.SetTo(B_PACKAGE_INFO_PRE_UNINSTALL_SCRIPTS,
|
||||||
|
value.string);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (context->ignoreUnknownAttributes)
|
if (context->ignoreUnknownAttributes)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -559,6 +559,10 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
|
|||||||
_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_POST_INSTALL_SCRIPT,
|
_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_POST_INSTALL_SCRIPT,
|
||||||
packageInfo.PostInstallScripts(), attributeList);
|
packageInfo.PostInstallScripts(), attributeList);
|
||||||
|
|
||||||
|
// pre uninstall script list
|
||||||
|
_AddStringAttributeList(B_HPKG_ATTRIBUTE_ID_PACKAGE_PRE_UNINSTALL_SCRIPT,
|
||||||
|
packageInfo.PreUninstallScripts(), attributeList);
|
||||||
|
|
||||||
// checksum (optional, only exists in repositories)
|
// checksum (optional, only exists in repositories)
|
||||||
_AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM,
|
_AddStringAttributeIfNotEmpty(B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM,
|
||||||
packageInfo.Checksum(), attributeList);
|
packageInfo.Checksum(), attributeList);
|
||||||
|
|||||||
@@ -391,13 +391,18 @@ CommitTransactionHandler::_ApplyChanges()
|
|||||||
// move packages to activate to packages directory
|
// move packages to activate to packages directory
|
||||||
_AddPackagesToActivate();
|
_AddPackagesToActivate();
|
||||||
|
|
||||||
|
// run pre-uninstall scripts, before their packages vanish.
|
||||||
|
_RunPreUninstallScripts();
|
||||||
|
|
||||||
// activate/deactivate packages
|
// activate/deactivate packages
|
||||||
_ChangePackageActivation(fAddedPackages, fRemovedPackages);
|
_ChangePackageActivation(fAddedPackages, fRemovedPackages);
|
||||||
|
|
||||||
|
// run post-installation scripts
|
||||||
if (fVolumeStateIsActive) {
|
if (fVolumeStateIsActive) {
|
||||||
// run post-installation scripts
|
|
||||||
_RunPostInstallScripts();
|
_RunPostInstallScripts();
|
||||||
} else {
|
} else {
|
||||||
|
// need to reboot to finish installation so queue up scripts as
|
||||||
|
// symbolic links in a work directory, which will run later.
|
||||||
_QueuePostInstallScripts();
|
_QueuePostInstallScripts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1303,7 +1308,7 @@ CommitTransactionHandler::_RunPostInstallScripts()
|
|||||||
const BStringList& scripts = package->Info().PostInstallScripts();
|
const BStringList& scripts = package->Info().PostInstallScripts();
|
||||||
int32 count = scripts.CountStrings();
|
int32 count = scripts.CountStrings();
|
||||||
for (int32 i = 0; i < count; i++)
|
for (int32 i = 0; i < count; i++)
|
||||||
_RunPostInstallScript(package, scripts.StringAt(i));
|
_RunPostOrPreScript(package, scripts.StringAt(i), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fCurrentPackage = NULL;
|
fCurrentPackage = NULL;
|
||||||
@@ -1311,19 +1316,42 @@ CommitTransactionHandler::_RunPostInstallScripts()
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CommitTransactionHandler::_RunPostInstallScript(Package* package,
|
CommitTransactionHandler::_RunPreUninstallScripts()
|
||||||
const BString& script)
|
|
||||||
{
|
{
|
||||||
|
// Note this runs in the correct order, so dependents get uninstalled before
|
||||||
|
// the packages they depend on. No need for a reversed loop.
|
||||||
|
for (PackageSet::iterator it = fPackagesToDeactivate.begin();
|
||||||
|
it != fPackagesToDeactivate.end(); ++it) {
|
||||||
|
Package* package = *it;
|
||||||
|
fCurrentPackage = package;
|
||||||
|
const BStringList& scripts = package->Info().PreUninstallScripts();
|
||||||
|
int32 count = scripts.CountStrings();
|
||||||
|
for (int32 i = 0; i < count; i++)
|
||||||
|
_RunPostOrPreScript(package, scripts.StringAt(i), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fCurrentPackage = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CommitTransactionHandler::_RunPostOrPreScript(Package* package,
|
||||||
|
const BString& script, bool postNotPre)
|
||||||
|
{
|
||||||
|
const char *postOrPreInstallWording = postNotPre
|
||||||
|
? "post-installation" : "pre-uninstall";
|
||||||
BDirectory rootDir(&fVolume->RootDirectoryRef());
|
BDirectory rootDir(&fVolume->RootDirectoryRef());
|
||||||
BPath scriptPath(&rootDir, script);
|
BPath scriptPath(&rootDir, script);
|
||||||
status_t error = scriptPath.InitCheck();
|
status_t error = scriptPath.InitCheck();
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
ERROR("Volume::CommitTransactionHandler::_RunPostInstallScript(): "
|
ERROR("Volume::CommitTransactionHandler::_RunPostOrPreScript(): "
|
||||||
"failed get path of post-installation script \"%s\" of package "
|
"failed get path of %s script \"%s\" of package "
|
||||||
"%s: %s\n", script.String(), package->FileName().String(),
|
"%s: %s\n",
|
||||||
strerror(error));
|
postOrPreInstallWording, script.String(),
|
||||||
_AddIssue(TransactionIssueBuilder(
|
package->FileName().String(), strerror(error));
|
||||||
BTransactionIssue::B_POST_INSTALL_SCRIPT_NOT_FOUND)
|
_AddIssue(TransactionIssueBuilder(postNotPre
|
||||||
|
? BTransactionIssue::B_POST_INSTALL_SCRIPT_NOT_FOUND
|
||||||
|
: BTransactionIssue::B_PRE_UNINSTALL_SCRIPT_NOT_FOUND)
|
||||||
.SetPath1(script)
|
.SetPath1(script)
|
||||||
.SetSystemError(error));
|
.SetSystemError(error));
|
||||||
return;
|
return;
|
||||||
@@ -1332,19 +1360,21 @@ CommitTransactionHandler::_RunPostInstallScript(Package* package,
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
int result = system(scriptPath.Path());
|
int result = system(scriptPath.Path());
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
ERROR("Volume::CommitTransactionHandler::_RunPostInstallScript(): "
|
ERROR("Volume::CommitTransactionHandler::_RunPostOrPreScript(): "
|
||||||
"running post-installation script \"%s\" of package %s "
|
"running %s script \"%s\" of package %s "
|
||||||
"failed: %d (errno: %s)\n", script.String(),
|
"failed: %d (errno: %s)\n",
|
||||||
package->FileName().String(), result,
|
postOrPreInstallWording, script.String(),
|
||||||
strerror(errno));
|
package->FileName().String(), result, strerror(errno));
|
||||||
if (result < 0 && errno != 0) {
|
if (result < 0 || result == 127) { // bash shell returns 127 on failure.
|
||||||
_AddIssue(TransactionIssueBuilder(
|
_AddIssue(TransactionIssueBuilder(postNotPre
|
||||||
BTransactionIssue::B_POST_INSTALL_SCRIPT_FAILED)
|
? BTransactionIssue::B_STARTING_POST_INSTALL_SCRIPT_FAILED
|
||||||
|
: BTransactionIssue::B_STARTING_PRE_UNINSTALL_SCRIPT_FAILED)
|
||||||
.SetPath1(BString(scriptPath.Path()))
|
.SetPath1(BString(scriptPath.Path()))
|
||||||
.SetSystemError(errno));
|
.SetSystemError(errno));
|
||||||
} else {
|
} else { // positive is an exit code from the script itself.
|
||||||
_AddIssue(TransactionIssueBuilder(
|
_AddIssue(TransactionIssueBuilder(postNotPre
|
||||||
BTransactionIssue::B_STARTING_POST_INSTALL_SCRIPT_FAILED)
|
? BTransactionIssue::B_POST_INSTALL_SCRIPT_FAILED
|
||||||
|
: BTransactionIssue::B_PRE_UNINSTALL_SCRIPT_FAILED)
|
||||||
.SetPath1(BString(scriptPath.Path()))
|
.SetPath1(BString(scriptPath.Path()))
|
||||||
.SetExitCode(result));
|
.SetExitCode(result));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,8 +97,10 @@ private:
|
|||||||
void _RevertUserGroupChanges();
|
void _RevertUserGroupChanges();
|
||||||
|
|
||||||
void _RunPostInstallScripts();
|
void _RunPostInstallScripts();
|
||||||
void _RunPostInstallScript(Package* package,
|
void _RunPreUninstallScripts();
|
||||||
const BString& script);
|
void _RunPostOrPreScript(Package* package,
|
||||||
|
const BString& script,
|
||||||
|
bool postNotPre);
|
||||||
|
|
||||||
void _QueuePostInstallScripts();
|
void _QueuePostInstallScripts();
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ private:
|
|||||||
status_t _InitLatestState();
|
status_t _InitLatestState();
|
||||||
status_t _InitLatestStateFromActivatedPackages();
|
status_t _InitLatestStateFromActivatedPackages();
|
||||||
status_t _GetActivePackages(int fd);
|
status_t _GetActivePackages(int fd);
|
||||||
void _RunQueuedScripts();
|
void _RunQueuedScripts(); // TODO: Never called, fix?
|
||||||
bool _CheckActivePackagesMatchLatestState(
|
bool _CheckActivePackagesMatchLatestState(
|
||||||
PackageFSGetPackageInfosRequest* request);
|
PackageFSGetPackageInfosRequest* request);
|
||||||
void _SetLatestState(VolumeState* state,
|
void _SetLatestState(VolumeState* state,
|
||||||
|
|||||||
Reference in New Issue
Block a user