Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(560)

Side by Side Diff: chrome/installer/util/installer_state.cc

Issue 6288009: More installer refactoring in the interest of fixing some bugs and cleaning t... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/installer/util/installer_state.h" 5 #include "chrome/installer/util/installer_state.h"
6 6
7 #include <algorithm>
8 #include <functional>
9 #include <utility>
10
11 #include "base/command_line.h"
12 #include "base/file_util.h"
7 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/scoped_ptr.h"
15 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/installer/util/delete_tree_work_item.h"
18 #include "chrome/installer/util/helper.h"
8 #include "chrome/installer/util/installation_state.h" 19 #include "chrome/installer/util/installation_state.h"
9 #include "chrome/installer/util/master_preferences.h" 20 #include "chrome/installer/util/master_preferences.h"
10 #include "chrome/installer/util/master_preferences_constants.h" 21 #include "chrome/installer/util/master_preferences_constants.h"
11 #include "chrome/installer/util/package_properties.h" 22 #include "chrome/installer/util/product.h"
23 #include "chrome/installer/util/work_item.h"
12 24
13 namespace installer { 25 namespace installer {
14 26
15 bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs, 27 bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs,
16 const InstallationState& machine_state) { 28 const InstallationState& machine_state) {
17 // First, is the package present? 29 // First, is the package present?
18 const ProductState* package = 30 const ProductState* package =
19 machine_state.GetMultiPackageState(system_install_); 31 machine_state.GetProductState(level_ == SYSTEM_LEVEL,
32 BrowserDistribution::CHROME_BINARIES);
20 if (package == NULL) { 33 if (package == NULL) {
21 // The multi-install package has not been installed, so it certainly isn't 34 // The multi-install package has not been installed, so it certainly isn't
22 // being updated. 35 // being updated.
23 return false; 36 return false;
24 } 37 }
25 38
26 BrowserDistribution::Type types[2]; 39 BrowserDistribution::Type types[2];
27 size_t num_types = 0; 40 size_t num_types = 0;
28 if (prefs.install_chrome()) 41 if (prefs.install_chrome())
29 types[num_types++] = BrowserDistribution::CHROME_BROWSER; 42 types[num_types++] = BrowserDistribution::CHROME_BROWSER;
30 if (prefs.install_chrome_frame()) 43 if (prefs.install_chrome_frame())
31 types[num_types++] = BrowserDistribution::CHROME_FRAME; 44 types[num_types++] = BrowserDistribution::CHROME_FRAME;
32 45
33 for (const BrowserDistribution::Type* scan = &types[0], 46 for (const BrowserDistribution::Type* scan = &types[0],
34 *end = &types[num_types]; scan != end; ++scan) { 47 *end = &types[num_types]; scan != end; ++scan) {
35 const ProductState* product = 48 const ProductState* product =
36 machine_state.GetProductState(system_install_, *scan); 49 machine_state.GetProductState(level_ == SYSTEM_LEVEL, *scan);
37 if (product == NULL) { 50 if (product == NULL) {
38 VLOG(2) << "It seems that distribution type " << *scan 51 VLOG(2) << "It seems that distribution type " << *scan
39 << " is being installed for the first time."; 52 << " is being installed for the first time.";
40 return false; 53 return false;
41 } 54 }
42 if (!product->channel().Equals(package->channel())) { 55 if (!product->channel().Equals(package->channel())) {
43 VLOG(2) << "It seems that distribution type " << *scan 56 VLOG(2) << "It seems that distribution type " << *scan
44 << " is being over installed."; 57 << " is being over installed.";
45 return false; 58 return false;
46 } 59 }
47 } 60 }
48 61
49 VLOG(2) << "It seems that the package is being updated."; 62 VLOG(2) << "It seems that the package is being updated.";
50 63
51 return true; 64 return true;
52 } 65 }
53 66
54 InstallerState::InstallerState() : operation_(UNINITIALIZED) { 67 InstallerState::InstallerState()
55 } 68 : operation_(UNINITIALIZED),
56 69 multi_package_distribution_(NULL),
57 void InstallerState::Initialize(const MasterPreferences& prefs, 70 level_(UNKNOWN_LEVEL),
71 package_type_(UNKNOWN_PACKAGE_TYPE),
72 root_key_(NULL),
73 msi_(false),
74 verbose_logging_(false) {
75 }
76
77 InstallerState::InstallerState(Level level)
78 : operation_(UNINITIALIZED),
79 multi_package_distribution_(NULL),
80 level_(level),
81 package_type_(UNKNOWN_PACKAGE_TYPE),
82 root_key_(NULL),
83 msi_(false),
84 verbose_logging_(false) {
85 }
86
87
88 void InstallerState::Initialize(const CommandLine& command_line,
89 const MasterPreferences& prefs,
58 const InstallationState& machine_state) { 90 const InstallationState& machine_state) {
59 if (!prefs.GetBool(installer::master_preferences::kSystemLevel, 91 bool pref_bool;
60 &system_install_)) 92 if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool))
61 system_install_ = false; 93 pref_bool = false;
94 level_ = (pref_bool ? SYSTEM_LEVEL : USER_LEVEL);
95
96 root_key_ = (level_ == SYSTEM_LEVEL ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
97
98 if (!prefs.GetBool(master_preferences::kVerboseLogging, &verbose_logging_))
tommi (sloooow) - chröme 2011/01/21 21:45:17 in order to get rid of this pattern we should add
grt (UTC plus 2) 2011/01/24 16:07:02 <nods head>
99 verbose_logging_ = false;
100
101 if (!prefs.GetBool(master_preferences::kMultiInstall, &pref_bool))
102 pref_bool = false;
103 package_type_ = (pref_bool ? MULTI_PACKAGE : SINGLE_PACKAGE);
104
105 if (!prefs.GetBool(master_preferences::kMsi, &msi_))
106 msi_ = false;
107
108 const bool is_uninstall = command_line.HasSwitch(switches::kUninstall);
109
110 if (prefs.install_chrome()) {
111 const Product& p =
112 AddProductFromPreferences(BrowserDistribution::CHROME_BROWSER, prefs,
113 machine_state);
114 VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
115 << " distribution: " << p.distribution()->GetApplicationName();
116 }
117 if (prefs.install_chrome_frame()) {
118 const Product& p =
119 AddProductFromPreferences(BrowserDistribution::CHROME_FRAME, prefs,
120 machine_state);
121 VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
122 << " distribution: " << p.distribution()->GetApplicationName();
123 }
124
125 // Operate in the Chrome Frame directory iff single install and installing
126 // CF. Otherwise, install in Chrome binaries directory.
127 if (package_type_ == SINGLE_PACKAGE && prefs.install_chrome_frame()) {
128 target_path_ = GetChromeInstallPath(
129 level_ == SYSTEM_LEVEL,
130 BrowserDistribution::GetSpecificDistribution(
131 BrowserDistribution::CHROME_FRAME));
132 } else {
133 target_path_ = GetChromeInstallPath(
134 level_ == SYSTEM_LEVEL,
135 BrowserDistribution::GetSpecificDistribution(
136 BrowserDistribution::CHROME_BINARIES));
137 }
138
139 if (package_type_ == MULTI_PACKAGE) {
140 multi_package_distribution_ =
141 BrowserDistribution::GetSpecificDistribution(
142 BrowserDistribution::CHROME_BINARIES);
143 }
62 144
63 BrowserDistribution* operand = NULL; 145 BrowserDistribution* operand = NULL;
64 146
65 if (!prefs.is_multi_install()) { 147 if (is_uninstall) {
148 operation_ = UNINSTALL;
149 } else if (!prefs.is_multi_install()) {
66 // For a single-install, the current browser dist is the operand. 150 // For a single-install, the current browser dist is the operand.
67 operand = BrowserDistribution::GetDistribution(); 151 operand = BrowserDistribution::GetDistribution();
68 operation_ = SINGLE_INSTALL_OR_UPDATE; 152 operation_ = SINGLE_INSTALL_OR_UPDATE;
69 } else if (IsMultiInstallUpdate(prefs, machine_state)) { 153 } else if (IsMultiInstallUpdate(prefs, machine_state)) {
70 // Updates driven by Google Update take place under the multi-installer's 154 // Updates driven by Google Update take place under the multi-installer's
71 // app guid. 155 // app guid.
72 installer::ActivePackageProperties package_properties; 156 operand = multi_package_distribution_;
73 operation_ = MULTI_UPDATE; 157 operation_ = MULTI_UPDATE;
74 state_key_ = package_properties.GetStateKey();
75 } else { 158 } else {
76 // Initial and over installs will always take place under one of the 159 // Initial and over installs will always take place under one of the
77 // product app guids. Chrome Frame's will be used if only Chrome Frame 160 // product app guids. Chrome Frame's will be used if only Chrome Frame
78 // is being installed. In all other cases, Chrome's is used. 161 // is being installed. In all other cases, Chrome's is used.
162 operation_ = MULTI_INSTALL;
163 }
164
165 if (operand == NULL) {
79 operand = BrowserDistribution::GetSpecificDistribution( 166 operand = BrowserDistribution::GetSpecificDistribution(
80 prefs.install_chrome() ? 167 prefs.install_chrome() ?
81 BrowserDistribution::CHROME_BROWSER : 168 BrowserDistribution::CHROME_BROWSER :
82 BrowserDistribution::CHROME_FRAME, 169 BrowserDistribution::CHROME_FRAME);
83 prefs); 170 }
84 operation_ = MULTI_INSTALL; 171
85 } 172 state_key_ = operand->GetStateKey();
86 173 }
87 if (operand != NULL) { 174
88 state_key_ = operand->GetStateKey(); 175 void InstallerState::ResetProducts() {
89 } 176 operation_ = UNINITIALIZED;
177 target_path_.clear();
178 products_.reset();
179 multi_package_distribution_ = NULL;
180 package_type_ = UNKNOWN_PACKAGE_TYPE;
181 msi_ = false;
182 }
183
184 const Product& InstallerState::AddProductFromPreferences(
185 BrowserDistribution::Type distribution_type,
186 const MasterPreferences& prefs,
187 const InstallationState& machine_state) {
188 scoped_ptr<Product> product(
189 new Product(BrowserDistribution::GetSpecificDistribution(
190 distribution_type)));
191 if (!msi_) {
192 const ProductState* product_state = machine_state.GetProductState(
193 level_ == SYSTEM_LEVEL, distribution_type);
194 if (product_state != NULL)
195 msi_ = product_state->msi();
196 }
197 product->InitializeFromPreferences(prefs);
198 products_.push_back(product.release());
199 return *products_[products_.size() - 1];
200 }
201
202 Product* InstallerState::AddProductFromState(
203 BrowserDistribution::Type type,
204 const ProductState& state) {
robertshield 2011/01/21 16:58:56 This method should return NULL when package_type_
grt (UTC plus 2) 2011/01/24 16:07:02 Done. Also if the target_path would conflict.
205 DCHECK_NE(SINGLE_PACKAGE, package_type_)
206 << "Cannot process more than one single-install product at a time.";
207 scoped_ptr<Product> product(
208 new Product(BrowserDistribution::GetSpecificDistribution(type)));
209 product->InitializeFromUninstallCommand(state.uninstall_command());
210 products_.push_back(product.release());
211 if (package_type_ == UNKNOWN_PACKAGE_TYPE) {
212 package_type_ = state.multi_install() ? MULTI_PACKAGE : SINGLE_PACKAGE;
213 if (package_type_ == MULTI_PACKAGE)
214 multi_package_distribution_ =
215 BrowserDistribution::GetSpecificDistribution(
216 BrowserDistribution::CHROME_BINARIES);
217 // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory().
218 target_path_ = state.GetSetupPath().DirName().DirName().DirName();
219 // Use the ClientState key of the first product added.
220 state_key_ = products_[products_.size() - 1]->distribution()->GetStateKey();
221 } else {
222 DCHECK_EQ(MULTI_PACKAGE, package_type_);
223 DCHECK(state.multi_install());
224 DCHECK_EQ(target_path_.value(),
225 state.GetSetupPath().DirName().DirName().DirName().value());
226 }
227 msi_ |= state.msi();
228 return products_[products_.size() - 1];
229 }
230
231 bool InstallerState::RemoveProduct(const Product* product) {
232 ScopedVector<Product>::iterator it =
233 std::find(products_.begin(), products_.end(), product);
tommi (sloooow) - chröme 2011/01/21 21:45:17 indent
grt (UTC plus 2) 2011/01/24 16:07:02 Done.
234 if (it != products_.end()) {
235 products_->erase(it);
236 return true;
237 }
238 return false;
239 }
240
241 const Product* InstallerState::FindProduct(
242 BrowserDistribution::Type distribution_type) const {
243 const Products::const_iterator it =
244 std::find_if(products_.begin(), products_.end(),
245 std::bind2nd(std::mem_fun(&Product::is_type),
246 distribution_type));
tommi (sloooow) - chröme 2011/01/21 21:45:17 this feels less readable to me than a simple loop
grt (UTC plus 2) 2011/01/24 16:07:02 Okay.
247 return it == products_.end() ? NULL : *it;
248 }
249
250 Version* InstallerState::GetCurrentVersion(
251 const InstallationState& machine_state) const {
252 DCHECK(!products_.empty());
253 scoped_ptr<Version> current_version;
254 const BrowserDistribution::Type prod_type = (package_type_ == MULTI_PACKAGE) ?
255 BrowserDistribution::CHROME_BINARIES :
256 products_[0]->distribution()->GetType();
257 const ProductState* product_state =
258 machine_state.GetProductState(level_ == SYSTEM_LEVEL, prod_type);
259
260 if (product_state != NULL) {
261 const Version* version = NULL;
262
263 // Be aware that there might be a pending "new_chrome.exe" already in the
264 // installation path. If so, we use old_version, which holds the version of
265 // "chrome.exe" itself.
266 if (file_util::PathExists(target_path().Append(kChromeNewExe)))
267 version = product_state->old_version();
268
269 if (version == NULL)
270 version = &product_state->version();
271
272 current_version.reset(version->Clone());
273 }
274
275 return current_version.release();
276 }
277
278 FilePath InstallerState::GetInstallerDirectory(const Version& version) const {
279 return target_path().Append(ASCIIToWide(version.GetString()))
280 .Append(kInstallerDir);
281 }
282
283 void InstallerState::RemoveOldVersionDirectories(
284 const Version& latest_version) const {
285 file_util::FileEnumerator version_enum(target_path(), false,
286 file_util::FileEnumerator::DIRECTORIES);
287 scoped_ptr<Version> version;
288 std::vector<FilePath> key_files;
289
290 // We try to delete all directories whose versions are lower than
291 // latest_version.
292 FilePath next_version = version_enum.Next();
293 while (!next_version.empty()) {
294 file_util::FileEnumerator::FindInfo find_data = {0};
295 version_enum.GetFindInfo(&find_data);
296 VLOG(1) << "directory found: " << find_data.cFileName;
297 version.reset(Version::GetVersionFromString(
298 WideToASCII(find_data.cFileName)));
299 if (version.get() && (latest_version.CompareTo(*version) > 0)) {
tommi (sloooow) - chröme 2011/01/21 21:45:17 no need for () around latest_version check.
grt (UTC plus 2) 2011/01/24 16:07:02 Done.
300 key_files.clear();
301 std::for_each(products_.begin(), products_.end(),
302 std::bind2nd(std::mem_fun(&Product::AddKeyFiles),
303 &key_files));
304 const std::vector<FilePath>::iterator end = key_files.end();
305 for (std::vector<FilePath>::iterator scan = key_files.begin();
306 scan != end; ++scan) {
307 *scan = next_version.Append(*scan);
308 }
309
310 VLOG(1) << "Deleting directory: " << next_version.value();
311
312 scoped_ptr<WorkItem> item(
313 WorkItem::CreateDeleteTreeWorkItem(next_version, key_files));
314 if (!item->Do())
315 item->Rollback();
316 }
317
318 next_version = version_enum.Next();
319 }
320 }
321
322 void InstallerState::AddComDllList(std::vector<FilePath>* com_dll_list) const {
323 std::for_each(products_.begin(), products_.end(),
324 std::bind2nd(std::mem_fun(&Product::AddComDllList),
325 com_dll_list));
326 }
327
328 bool InstallerState::SetChannelFlags(bool set,
329 ChannelInfo* channel_info) const {
330 bool modified = false;
331
332 // We don't have access to lambdas yet, but we can sure fake it!.
333 struct SetChannelFlagsFunc
334 : public std::unary_function<const Product*, void> {
335 public:
336 SetChannelFlagsFunc(bool set, ChannelInfo* channel_info, bool* modified)
337 : channel_info_(channel_info), modified_(modified), set_(set) {}
338 result_type operator()(argument_type product) const {
339 *modified_ |= product->SetChannelFlags(set_, channel_info_);
340 }
341 private:
342 ChannelInfo* channel_info_;
343 bool* modified_;
344 bool set_;
345 };
346
347 std::for_each(products_.begin(), products_.end(),
348 SetChannelFlagsFunc(set, channel_info, &modified));
349 return modified;
robertshield 2011/01/21 19:37:47 this is neat, but the following (or a non-broken v
tommi (sloooow) - chröme 2011/01/21 21:45:17 +1
grt (UTC plus 2) 2011/01/24 16:07:02 Okay. I can't wait for lambdas...
90 } 350 }
91 351
92 } // namespace installer 352 } // namespace installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698