2 * Copyright (c) 2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
6 * Ćukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
10 #include "PackageInstall.h"
12 #include "InstalledPackageInfo.h"
13 #include "PackageItem.h"
14 #include "PackageView.h"
22 #undef B_TRANSLATION_CONTEXT
23 #define B_TRANSLATION_CONTEXT "PackageInstall"
27 install_function(void* data
)
29 // TODO: Inform if already one thread is running
33 PackageInstall
* install
= static_cast<PackageInstall
*>(data
);
39 PackageInstall::PackageInstall(PackageView
* parent
)
48 PackageInstall::~PackageInstall()
54 PackageInstall::Start()
62 fThreadId
= spawn_thread(install_function
, "install_package",
63 B_NORMAL_PRIORITY
, this);
64 resume_thread(fThreadId
);
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.
80 kill_thread(fThreadId
);
85 fCurrentScriptLocker
.Lock();
86 if (fCurrentScript
!= NULL
) {
87 thread_id id
= fCurrentScript
->GetThreadId();
89 fCurrentScript
->SetThreadId(-1);
92 fCurrentScript
= NULL
;
94 fCurrentScriptLocker
.Unlock();
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%"));
117 indexString
<< (index
+ 1);
119 totalString
<< total
;
120 label
.ReplaceAll("%index%", indexString
);
121 label
.ReplaceAll("%total%", totalString
);
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();
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();
157 fprintf(stderr
, "Error uninstalling previously installed "
158 "package: %s\n", strerror(err
));
162 err
= packageInfo
.SetTo(info
->GetName(), info
->GetVersion(), true);
164 fprintf(stderr
, "Error marking installation of package: "
165 "%s\n", strerror(err
));
166 return P_MSG_I_ERROR
;
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);
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
;
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
,
216 if (choice
!= P_EXISTS_ABORT
) {
217 state
.policy
= choice
;
218 err
= item
->DoInstall(installPath
, &state
);
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
;
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"),
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",
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();
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
;