btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / packageinstaller / PackageInstall.cpp
blob4a7ecc778625f7326bf425d08ecf5c69f90596f4
1 /*
2 * Copyright (c) 2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
5 * Author:
6 * Ɓukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
7 */
10 #include "PackageInstall.h"
12 #include "InstalledPackageInfo.h"
13 #include "PackageItem.h"
14 #include "PackageView.h"
16 #include <Alert.h>
17 #include <Catalog.h>
18 #include <Locale.h>
19 #include <stdio.h>
22 #undef B_TRANSLATION_CONTEXT
23 #define B_TRANSLATION_CONTEXT "PackageInstall"
26 static int32
27 install_function(void* data)
29 // TODO: Inform if already one thread is running
30 if (data == NULL)
31 return -1;
33 PackageInstall* install = static_cast<PackageInstall*>(data);
34 install->Install();
35 return 0;
39 PackageInstall::PackageInstall(PackageView* parent)
41 fParent(parent),
42 fThreadId(-1),
43 fCurrentScript(NULL)
48 PackageInstall::~PackageInstall()
53 status_t
54 PackageInstall::Start()
56 status_t ret = B_OK;
58 fIdLocker.Lock();
59 if (fThreadId > -1) {
60 ret = B_BUSY;
61 } else {
62 fThreadId = spawn_thread(install_function, "install_package",
63 B_NORMAL_PRIORITY, this);
64 resume_thread(fThreadId);
66 fIdLocker.Unlock();
68 return ret;
72 void
73 PackageInstall::Stop()
75 // TODO: Argh! No killing of threads!! That leaks resources which they
76 // allocated. Rather inform them they need to quit, which they do at the
77 // next convenient time, then use wait_for_thread() here.
78 fIdLocker.Lock();
79 if (fThreadId > -1) {
80 kill_thread(fThreadId);
81 fThreadId = -1;
83 fIdLocker.Unlock();
85 fCurrentScriptLocker.Lock();
86 if (fCurrentScript != NULL) {
87 thread_id id = fCurrentScript->GetThreadId();
88 if (id > -1) {
89 fCurrentScript->SetThreadId(-1);
90 kill_thread(id);
92 fCurrentScript = NULL;
94 fCurrentScriptLocker.Unlock();
98 void
99 PackageInstall::Install()
101 // A message sending wrapper around _Install()
102 uint32 code = _Install();
104 BMessenger messenger(fParent);
105 if (messenger.IsValid()) {
106 BMessage message(code);
107 messenger.SendMessage(&message);
112 static inline BString
113 get_item_progress_string(uint32 index, uint32 total)
115 BString label(B_TRANSLATE("%index% of %total%"));
116 BString indexString;
117 indexString << (index + 1);
118 BString totalString;
119 totalString << total;
120 label.ReplaceAll("%index%", indexString);
121 label.ReplaceAll("%total%", totalString);
122 return label;
126 uint32
127 PackageInstall::_Install()
129 PackageInfo* info = fParent->GetPackageInfo();
130 pkg_profile* type = static_cast<pkg_profile*>(info->GetProfile(
131 fParent->CurrentType()));
132 uint32 n = type->items.CountItems();
133 uint32 m = info->GetScriptCount();
135 PackageStatus* progress = fParent->StatusWindow();
136 progress->Reset(n + m + 5);
138 progress->StageStep(1, B_TRANSLATE("Preparing package"));
140 InstalledPackageInfo packageInfo(info->GetName(), info->GetVersion());
142 status_t err = packageInfo.InitCheck();
143 if (err == B_OK) {
144 // The package is already installed, inform the user
145 BAlert* reinstall = new BAlert("reinstall",
146 B_TRANSLATE("The given package seems to be already installed on "
147 "your system. Would you like to uninstall the existing one "
148 "and continue the installation?"),
149 B_TRANSLATE("Continue"),
150 B_TRANSLATE("Abort"));
151 reinstall->SetShortcut(1, B_ESCAPE);
153 if (reinstall->Go() == 0) {
154 // Uninstall the package
155 err = packageInfo.Uninstall();
156 if (err != B_OK) {
157 fprintf(stderr, "Error uninstalling previously installed "
158 "package: %s\n", strerror(err));
159 // Ignore error
162 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true);
163 if (err != B_OK) {
164 fprintf(stderr, "Error marking installation of package: "
165 "%s\n", strerror(err));
166 return P_MSG_I_ERROR;
168 } else {
169 // Abort the installation
170 return P_MSG_I_ABORT;
172 } else if (err == B_ENTRY_NOT_FOUND) {
173 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true);
174 if (err != B_OK) {
175 fprintf(stderr, "Error marking installation of package: "
176 "%s\n", strerror(err));
177 return P_MSG_I_ERROR;
179 } else if (progress->Stopped()) {
180 return P_MSG_I_ABORT;
181 } else {
182 fprintf(stderr, "returning on error\n");
183 return P_MSG_I_ERROR;
186 progress->StageStep(1, B_TRANSLATE("Installing files and folders"));
188 // Install files and directories
190 packageInfo.SetName(info->GetName());
191 // TODO: Here's a small problem, since right now it's not quite sure
192 // which description is really used as such. The one displayed on
193 // the installer is mostly package installation description, but
194 // most people use it for describing the application in more detail
195 // then in the short description.
196 // For now, we'll use the short description if possible.
197 BString description = info->GetShortDescription();
198 if (description.Length() <= 0)
199 description = info->GetDescription();
200 packageInfo.SetDescription(description.String());
201 packageInfo.SetSpaceNeeded(type->space_needed);
203 fItemExistsPolicy = P_EXISTS_NONE;
205 const char* installPath = fParent->CurrentPath()->Path();
206 for (uint32 i = 0; i < n; i++) {
207 ItemState state(fItemExistsPolicy);
208 PackageItem* item = static_cast<PackageItem*>(type->items.ItemAt(i));
210 err = item->DoInstall(installPath, &state);
211 if (err == B_FILE_EXISTS) {
212 // Writing to path failed because path already exists - ask the user
213 // what to do and retry the writing process
214 int32 choice = fParent->ItemExists(*item, state.destination,
215 fItemExistsPolicy);
216 if (choice != P_EXISTS_ABORT) {
217 state.policy = choice;
218 err = item->DoInstall(installPath, &state);
222 if (err != B_OK) {
223 fprintf(stderr, "Error '%s' while writing path\n", strerror(err));
224 return P_MSG_I_ERROR;
227 if (progress->Stopped())
228 return P_MSG_I_ABORT;
230 // Update progress
231 progress->StageStep(1, NULL, get_item_progress_string(i, n).String());
233 // Mark installed item in packageInfo
234 packageInfo.AddItem(state.destination.Path());
237 progress->StageStep(1, B_TRANSLATE("Running post-installation scripts"),
238 "");
240 // Run all scripts
241 // TODO: Change current working directory to installation location!
242 for (uint32 i = 0; i < m; i++) {
243 PackageScript* script = info->GetScript(i);
245 fCurrentScriptLocker.Lock();
246 fCurrentScript = script;
248 status_t status = script->DoInstall(installPath);
249 if (status != B_OK) {
250 fprintf(stderr, "Error while running script: %s\n",
251 strerror(status));
252 fCurrentScriptLocker.Unlock();
253 return P_MSG_I_ERROR;
255 fCurrentScriptLocker.Unlock();
257 wait_for_thread(script->GetThreadId(), &status);
259 fCurrentScriptLocker.Lock();
260 script->SetThreadId(-1);
261 fCurrentScript = NULL;
262 fCurrentScriptLocker.Unlock();
264 if (progress->Stopped())
265 return P_MSG_I_ABORT;
267 progress->StageStep(1, NULL, get_item_progress_string(i, m).String());
270 progress->StageStep(1, B_TRANSLATE("Finishing installation"), "");
272 err = packageInfo.Save();
273 if (err != B_OK)
274 return P_MSG_I_ERROR;
276 progress->StageStep(1, B_TRANSLATE("Done"));
278 // Inform our parent that we finished
279 return P_MSG_I_FINISHED;