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_TRANSLATE_CONTEXT 23 #define B_TRANSLATE_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 129 if (reinstall->Go() == 0) { 130 // Uninstall the package 131 err = packageInfo.Uninstall(); 132 if (err != B_OK) { 133 fprintf(stderr, "Error on uninstall\n"); 134 return P_MSG_I_ERROR; 135 } 136 137 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true); 138 if (err != B_OK) { 139 fprintf(stderr, "Error on SetTo\n"); 140 return P_MSG_I_ERROR; 141 } 142 } else { 143 // Abort the installation 144 return P_MSG_I_ABORT; 145 } 146 } else if (err == B_ENTRY_NOT_FOUND) { 147 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true); 148 if (err != B_OK) { 149 fprintf(stderr, "Error on SetTo\n"); 150 return P_MSG_I_ERROR; 151 } 152 } else if (progress->Stopped()) { 153 return P_MSG_I_ABORT; 154 } else { 155 fprintf(stderr, "returning on error\n"); 156 return P_MSG_I_ERROR; 157 } 158 159 progress->StageStep(1, B_TRANSLATE("Installing files and folders")); 160 161 // Install files and directories 162 PackageItem *iter; 163 ItemState state; 164 uint32 i; 165 int32 choice; 166 BString label; 167 168 packageInfo.SetName(info->GetName()); 169 // TODO: Here's a small problem, since right now it's not quite sure 170 // which description is really used as such. The one displayed on 171 // the installer is mostly package installation description, but 172 // most people use it for describing the application in more detail 173 // then in the short description. 174 // For now, we'll use the short description if possible. 175 BString description = info->GetShortDescription(); 176 if (description.Length() <= 0) 177 description = info->GetDescription(); 178 packageInfo.SetDescription(description.String()); 179 packageInfo.SetSpaceNeeded(type->space_needed); 180 181 fItemExistsPolicy = P_EXISTS_NONE; 182 183 const char *installPath = fParent->GetCurrentPath()->Path(); 184 for (i = 0; i < n; i++) { 185 state.Reset(fItemExistsPolicy); // Reset the current item state 186 iter = static_cast<PackageItem *>(type->items.ItemAt(i)); 187 188 err = iter->DoInstall(installPath, &state); 189 if (err == B_FILE_EXISTS) { 190 // Writing to path failed because path already exists - ask the user 191 // what to do and retry the writing process 192 choice = fParent->ItemExists(*iter, state.destination, 193 fItemExistsPolicy); 194 if (choice != P_EXISTS_ABORT) { 195 state.policy = choice; 196 err = iter->DoInstall(installPath, &state); 197 } 198 } 199 200 if (err != B_OK) { 201 fprintf(stderr, "Error while writing path\n"); 202 return P_MSG_I_ERROR; 203 } 204 205 if (progress->Stopped()) 206 return P_MSG_I_ABORT; 207 label = ""; 208 label << (uint32)(i + 1) << " of " << (uint32)n; 209 progress->StageStep(1, NULL, label.String()); 210 211 packageInfo.AddItem(state.destination.Path()); 212 } 213 214 progress->StageStep(1, B_TRANSLATE("Running post-installation scripts"), 215 ""); 216 217 PackageScript *scr; 218 status_t status; 219 // Run all scripts 220 for (i = 0; i < m; i++) { 221 scr = info->GetScript(i); 222 223 fCurrentScriptLocker.Lock(); 224 fCurrentScript = scr; 225 226 if (scr->DoInstall() != B_OK) { 227 fprintf(stderr, "Error while running script\n"); 228 return P_MSG_I_ERROR; 229 } 230 fCurrentScriptLocker.Unlock(); 231 232 wait_for_thread(scr->GetThreadId(), &status); 233 fCurrentScriptLocker.Lock(); 234 scr->SetThreadId(-1); 235 fCurrentScript = NULL; 236 fCurrentScriptLocker.Unlock(); 237 238 if (progress->Stopped()) 239 return P_MSG_I_ABORT; 240 label = ""; 241 label << (uint32)(i + 1) << " of " << (uint32)m; 242 progress->StageStep(1, NULL, label.String()); 243 } 244 245 progress->StageStep(1, B_TRANSLATE("Finishing installation"), ""); 246 247 err = packageInfo.Save(); 248 if (err != B_OK) 249 return P_MSG_I_ERROR; 250 251 progress->StageStep(1, B_TRANSLATE("Done")); 252 253 // Inform our parent that we finished 254 return P_MSG_I_FINISHED; 255 } 256 257