1 /* 2 * Copyright (c) 2010, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org> 7 */ 8 9 10 #include "PackageInstall.h" 11 12 #include "InstalledPackageInfo.h" 13 #include "PackageItem.h" 14 #include "PackageView.h" 15 16 #include <Alert.h> 17 #include <Catalog.h> 18 #include <Locale.h> 19 #include <stdio.h> 20 21 22 #undef B_TRANSLATION_CONTEXT 23 #define B_TRANSLATION_CONTEXT "PackageInstall" 24 25 26 static int32 27 install_function(void *data) 28 { 29 // TODO: Inform if already one thread is running 30 PackageInstall *install = static_cast<PackageInstall *>(data); 31 if (data == NULL) 32 return -1; 33 34 install->Install(); 35 return 0; 36 } 37 38 39 PackageInstall::PackageInstall(PackageView *parent) 40 : fParent(parent), 41 fThreadId(-1), 42 fCurrentScript(NULL) 43 { 44 } 45 46 47 PackageInstall::~PackageInstall() 48 { 49 } 50 51 52 status_t 53 PackageInstall::Start() 54 { 55 status_t ret = B_OK; 56 57 fIdLocker.Lock(); 58 if (fThreadId > -1) { 59 ret = B_BUSY; 60 } else { 61 fThreadId = spawn_thread(install_function, "install_package", B_NORMAL_PRIORITY, 62 static_cast<void *>(this)); 63 resume_thread(fThreadId); 64 } 65 fIdLocker.Unlock(); 66 67 return ret; 68 } 69 70 71 void 72 PackageInstall::Stop() 73 { 74 fIdLocker.Lock(); 75 if (fThreadId > -1) { 76 kill_thread(fThreadId); 77 fThreadId = -1; 78 } 79 fIdLocker.Unlock(); 80 81 fCurrentScriptLocker.Lock(); 82 if (fCurrentScript != NULL) { 83 thread_id id = fCurrentScript->GetThreadId(); 84 if (id > -1) { 85 fCurrentScript->SetThreadId(-1); 86 kill_thread(id); 87 } 88 fCurrentScript = NULL; 89 } 90 fCurrentScriptLocker.Unlock(); 91 } 92 93 94 void 95 PackageInstall::Install() 96 { 97 // A message sending wrapper around _Install() 98 uint32 msg = _Install(); 99 if (fParent && fParent->Looper()) 100 fParent->Looper()->PostMessage(new BMessage(msg), fParent); 101 } 102 103 104 uint32 105 PackageInstall::_Install() 106 { 107 PackageInfo *info = fParent->GetPackageInfo(); 108 pkg_profile *type = static_cast<pkg_profile *>(info->GetProfile( 109 fParent->GetCurrentType())); 110 uint32 n = type->items.CountItems(), m = info->GetScriptCount(); 111 112 PackageStatus *progress = fParent->GetStatusWindow(); 113 progress->Reset(n + m + 5); 114 115 progress->StageStep(1, B_TRANSLATE("Preparing package")); 116 117 InstalledPackageInfo packageInfo(info->GetName(), info->GetVersion()); 118 119 status_t err = packageInfo.InitCheck(); 120 if (err == B_OK) { 121 // The package is already installed, inform the user 122 BAlert *reinstall = new BAlert("reinstall", 123 B_TRANSLATE("The given package seems to be already installed on " 124 "your system. Would you like to uninstall the existing one " 125 "and continue the installation?"), 126 B_TRANSLATE("Continue"), 127 B_TRANSLATE("Abort")); 128 reinstall->SetShortcut(1, B_ESCAPE); 129 130 if (reinstall->Go() == 0) { 131 // Uninstall the package 132 err = packageInfo.Uninstall(); 133 if (err != B_OK) { 134 fprintf(stderr, "Error on uninstall\n"); 135 return P_MSG_I_ERROR; 136 } 137 138 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true); 139 if (err != B_OK) { 140 fprintf(stderr, "Error on SetTo\n"); 141 return P_MSG_I_ERROR; 142 } 143 } else { 144 // Abort the installation 145 return P_MSG_I_ABORT; 146 } 147 } else if (err == B_ENTRY_NOT_FOUND) { 148 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true); 149 if (err != B_OK) { 150 fprintf(stderr, "Error on SetTo\n"); 151 return P_MSG_I_ERROR; 152 } 153 } else if (progress->Stopped()) { 154 return P_MSG_I_ABORT; 155 } else { 156 fprintf(stderr, "returning on error\n"); 157 return P_MSG_I_ERROR; 158 } 159 160 progress->StageStep(1, B_TRANSLATE("Installing files and folders")); 161 162 // Install files and directories 163 PackageItem *iter; 164 ItemState state; 165 uint32 i; 166 int32 choice; 167 BString label; 168 169 packageInfo.SetName(info->GetName()); 170 // TODO: Here's a small problem, since right now it's not quite sure 171 // which description is really used as such. The one displayed on 172 // the installer is mostly package installation description, but 173 // most people use it for describing the application in more detail 174 // then in the short description. 175 // For now, we'll use the short description if possible. 176 BString description = info->GetShortDescription(); 177 if (description.Length() <= 0) 178 description = info->GetDescription(); 179 packageInfo.SetDescription(description.String()); 180 packageInfo.SetSpaceNeeded(type->space_needed); 181 182 fItemExistsPolicy = P_EXISTS_NONE; 183 184 const char *installPath = fParent->GetCurrentPath()->Path(); 185 for (i = 0; i < n; i++) { 186 state.Reset(fItemExistsPolicy); // Reset the current item state 187 iter = static_cast<PackageItem *>(type->items.ItemAt(i)); 188 189 err = iter->DoInstall(installPath, &state); 190 if (err == B_FILE_EXISTS) { 191 // Writing to path failed because path already exists - ask the user 192 // what to do and retry the writing process 193 choice = fParent->ItemExists(*iter, state.destination, 194 fItemExistsPolicy); 195 if (choice != P_EXISTS_ABORT) { 196 state.policy = choice; 197 err = iter->DoInstall(installPath, &state); 198 } 199 } 200 201 if (err != B_OK) { 202 fprintf(stderr, "Error while writing path\n"); 203 return P_MSG_I_ERROR; 204 } 205 206 if (progress->Stopped()) 207 return P_MSG_I_ABORT; 208 label = ""; 209 label << (uint32)(i + 1) << " of " << (uint32)n; 210 progress->StageStep(1, NULL, label.String()); 211 212 packageInfo.AddItem(state.destination.Path()); 213 } 214 215 progress->StageStep(1, B_TRANSLATE("Running post-installation scripts"), 216 ""); 217 218 PackageScript *scr; 219 status_t status; 220 // Run all scripts 221 for (i = 0; i < m; i++) { 222 scr = info->GetScript(i); 223 224 fCurrentScriptLocker.Lock(); 225 fCurrentScript = scr; 226 227 if (scr->DoInstall() != B_OK) { 228 fprintf(stderr, "Error while running script\n"); 229 return P_MSG_I_ERROR; 230 } 231 fCurrentScriptLocker.Unlock(); 232 233 wait_for_thread(scr->GetThreadId(), &status); 234 fCurrentScriptLocker.Lock(); 235 scr->SetThreadId(-1); 236 fCurrentScript = NULL; 237 fCurrentScriptLocker.Unlock(); 238 239 if (progress->Stopped()) 240 return P_MSG_I_ABORT; 241 label = ""; 242 label << (uint32)(i + 1) << " of " << (uint32)m; 243 progress->StageStep(1, NULL, label.String()); 244 } 245 246 progress->StageStep(1, B_TRANSLATE("Finishing installation"), ""); 247 248 err = packageInfo.Save(); 249 if (err != B_OK) 250 return P_MSG_I_ERROR; 251 252 progress->StageStep(1, B_TRANSLATE("Done")); 253 254 // Inform our parent that we finished 255 return P_MSG_I_FINISHED; 256 } 257 258