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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/installer/util/installer_state.cc
===================================================================
--- chrome/installer/util/installer_state.cc (revision 71802)
+++ chrome/installer/util/installer_state.cc (working copy)
@@ -4,11 +4,23 @@
#include "chrome/installer/util/installer_state.h"
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/product.h"
+#include "chrome/installer/util/work_item.h"
namespace installer {
@@ -16,7 +28,8 @@
const InstallationState& machine_state) {
// First, is the package present?
const ProductState* package =
- machine_state.GetMultiPackageState(system_install_);
+ machine_state.GetProductState(level_ == SYSTEM_LEVEL,
+ BrowserDistribution::CHROME_BINARIES);
if (package == NULL) {
// The multi-install package has not been installed, so it certainly isn't
// being updated.
@@ -33,7 +46,7 @@
for (const BrowserDistribution::Type* scan = &types[0],
*end = &types[num_types]; scan != end; ++scan) {
const ProductState* product =
- machine_state.GetProductState(system_install_, *scan);
+ machine_state.GetProductState(level_ == SYSTEM_LEVEL, *scan);
if (product == NULL) {
VLOG(2) << "It seems that distribution type " << *scan
<< " is being installed for the first time.";
@@ -51,42 +64,289 @@
return true;
}
-InstallerState::InstallerState() : operation_(UNINITIALIZED) {
+InstallerState::InstallerState()
+ : operation_(UNINITIALIZED),
+ multi_package_distribution_(NULL),
+ level_(UNKNOWN_LEVEL),
+ package_type_(UNKNOWN_PACKAGE_TYPE),
+ root_key_(NULL),
+ msi_(false),
+ verbose_logging_(false) {
}
-void InstallerState::Initialize(const MasterPreferences& prefs,
+InstallerState::InstallerState(Level level)
+ : operation_(UNINITIALIZED),
+ multi_package_distribution_(NULL),
+ level_(level),
+ package_type_(UNKNOWN_PACKAGE_TYPE),
+ root_key_(NULL),
+ msi_(false),
+ verbose_logging_(false) {
+}
+
+
+void InstallerState::Initialize(const CommandLine& command_line,
+ const MasterPreferences& prefs,
const InstallationState& machine_state) {
- if (!prefs.GetBool(installer::master_preferences::kSystemLevel,
- &system_install_))
- system_install_ = false;
+ bool pref_bool;
+ if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool))
+ pref_bool = false;
+ level_ = (pref_bool ? SYSTEM_LEVEL : USER_LEVEL);
+ root_key_ = (level_ == SYSTEM_LEVEL ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
+
+ 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>
+ verbose_logging_ = false;
+
+ if (!prefs.GetBool(master_preferences::kMultiInstall, &pref_bool))
+ pref_bool = false;
+ package_type_ = (pref_bool ? MULTI_PACKAGE : SINGLE_PACKAGE);
+
+ if (!prefs.GetBool(master_preferences::kMsi, &msi_))
+ msi_ = false;
+
+ const bool is_uninstall = command_line.HasSwitch(switches::kUninstall);
+
+ if (prefs.install_chrome()) {
+ const Product& p =
+ AddProductFromPreferences(BrowserDistribution::CHROME_BROWSER, prefs,
+ machine_state);
+ VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
+ << " distribution: " << p.distribution()->GetApplicationName();
+ }
+ if (prefs.install_chrome_frame()) {
+ const Product& p =
+ AddProductFromPreferences(BrowserDistribution::CHROME_FRAME, prefs,
+ machine_state);
+ VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
+ << " distribution: " << p.distribution()->GetApplicationName();
+ }
+
+ // Operate in the Chrome Frame directory iff single install and installing
+ // CF. Otherwise, install in Chrome binaries directory.
+ if (package_type_ == SINGLE_PACKAGE && prefs.install_chrome_frame()) {
+ target_path_ = GetChromeInstallPath(
+ level_ == SYSTEM_LEVEL,
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_FRAME));
+ } else {
+ target_path_ = GetChromeInstallPath(
+ level_ == SYSTEM_LEVEL,
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES));
+ }
+
+ if (package_type_ == MULTI_PACKAGE) {
+ multi_package_distribution_ =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ }
+
BrowserDistribution* operand = NULL;
- if (!prefs.is_multi_install()) {
+ if (is_uninstall) {
+ operation_ = UNINSTALL;
+ } else if (!prefs.is_multi_install()) {
// For a single-install, the current browser dist is the operand.
operand = BrowserDistribution::GetDistribution();
operation_ = SINGLE_INSTALL_OR_UPDATE;
} else if (IsMultiInstallUpdate(prefs, machine_state)) {
// Updates driven by Google Update take place under the multi-installer's
// app guid.
- installer::ActivePackageProperties package_properties;
+ operand = multi_package_distribution_;
operation_ = MULTI_UPDATE;
- state_key_ = package_properties.GetStateKey();
} else {
// Initial and over installs will always take place under one of the
// product app guids. Chrome Frame's will be used if only Chrome Frame
// is being installed. In all other cases, Chrome's is used.
+ operation_ = MULTI_INSTALL;
+ }
+
+ if (operand == NULL) {
operand = BrowserDistribution::GetSpecificDistribution(
prefs.install_chrome() ?
BrowserDistribution::CHROME_BROWSER :
- BrowserDistribution::CHROME_FRAME,
- prefs);
- operation_ = MULTI_INSTALL;
+ BrowserDistribution::CHROME_FRAME);
}
- if (operand != NULL) {
- state_key_ = operand->GetStateKey();
+ state_key_ = operand->GetStateKey();
+}
+
+void InstallerState::ResetProducts() {
+ operation_ = UNINITIALIZED;
+ target_path_.clear();
+ products_.reset();
+ multi_package_distribution_ = NULL;
+ package_type_ = UNKNOWN_PACKAGE_TYPE;
+ msi_ = false;
+}
+
+const Product& InstallerState::AddProductFromPreferences(
+ BrowserDistribution::Type distribution_type,
+ const MasterPreferences& prefs,
+ const InstallationState& machine_state) {
+ scoped_ptr<Product> product(
+ new Product(BrowserDistribution::GetSpecificDistribution(
+ distribution_type)));
+ if (!msi_) {
+ const ProductState* product_state = machine_state.GetProductState(
+ level_ == SYSTEM_LEVEL, distribution_type);
+ if (product_state != NULL)
+ msi_ = product_state->msi();
}
+ product->InitializeFromPreferences(prefs);
+ products_.push_back(product.release());
+ return *products_[products_.size() - 1];
}
+Product* InstallerState::AddProductFromState(
+ BrowserDistribution::Type type,
+ 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.
+ DCHECK_NE(SINGLE_PACKAGE, package_type_)
+ << "Cannot process more than one single-install product at a time.";
+ scoped_ptr<Product> product(
+ new Product(BrowserDistribution::GetSpecificDistribution(type)));
+ product->InitializeFromUninstallCommand(state.uninstall_command());
+ products_.push_back(product.release());
+ if (package_type_ == UNKNOWN_PACKAGE_TYPE) {
+ package_type_ = state.multi_install() ? MULTI_PACKAGE : SINGLE_PACKAGE;
+ if (package_type_ == MULTI_PACKAGE)
+ multi_package_distribution_ =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory().
+ target_path_ = state.GetSetupPath().DirName().DirName().DirName();
+ // Use the ClientState key of the first product added.
+ state_key_ = products_[products_.size() - 1]->distribution()->GetStateKey();
+ } else {
+ DCHECK_EQ(MULTI_PACKAGE, package_type_);
+ DCHECK(state.multi_install());
+ DCHECK_EQ(target_path_.value(),
+ state.GetSetupPath().DirName().DirName().DirName().value());
+ }
+ msi_ |= state.msi();
+ return products_[products_.size() - 1];
+}
+
+bool InstallerState::RemoveProduct(const Product* product) {
+ ScopedVector<Product>::iterator it =
+ 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.
+ if (it != products_.end()) {
+ products_->erase(it);
+ return true;
+ }
+ return false;
+}
+
+const Product* InstallerState::FindProduct(
+ BrowserDistribution::Type distribution_type) const {
+ const Products::const_iterator it =
+ std::find_if(products_.begin(), products_.end(),
+ std::bind2nd(std::mem_fun(&Product::is_type),
+ 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.
+ return it == products_.end() ? NULL : *it;
+}
+
+Version* InstallerState::GetCurrentVersion(
+ const InstallationState& machine_state) const {
+ DCHECK(!products_.empty());
+ scoped_ptr<Version> current_version;
+ const BrowserDistribution::Type prod_type = (package_type_ == MULTI_PACKAGE) ?
+ BrowserDistribution::CHROME_BINARIES :
+ products_[0]->distribution()->GetType();
+ const ProductState* product_state =
+ machine_state.GetProductState(level_ == SYSTEM_LEVEL, prod_type);
+
+ if (product_state != NULL) {
+ const Version* version = NULL;
+
+ // Be aware that there might be a pending "new_chrome.exe" already in the
+ // installation path. If so, we use old_version, which holds the version of
+ // "chrome.exe" itself.
+ if (file_util::PathExists(target_path().Append(kChromeNewExe)))
+ version = product_state->old_version();
+
+ if (version == NULL)
+ version = &product_state->version();
+
+ current_version.reset(version->Clone());
+ }
+
+ return current_version.release();
+}
+
+FilePath InstallerState::GetInstallerDirectory(const Version& version) const {
+ return target_path().Append(ASCIIToWide(version.GetString()))
+ .Append(kInstallerDir);
+}
+
+void InstallerState::RemoveOldVersionDirectories(
+ const Version& latest_version) const {
+ file_util::FileEnumerator version_enum(target_path(), false,
+ file_util::FileEnumerator::DIRECTORIES);
+ scoped_ptr<Version> version;
+ std::vector<FilePath> key_files;
+
+ // We try to delete all directories whose versions are lower than
+ // latest_version.
+ FilePath next_version = version_enum.Next();
+ while (!next_version.empty()) {
+ file_util::FileEnumerator::FindInfo find_data = {0};
+ version_enum.GetFindInfo(&find_data);
+ VLOG(1) << "directory found: " << find_data.cFileName;
+ version.reset(Version::GetVersionFromString(
+ WideToASCII(find_data.cFileName)));
+ 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.
+ key_files.clear();
+ std::for_each(products_.begin(), products_.end(),
+ std::bind2nd(std::mem_fun(&Product::AddKeyFiles),
+ &key_files));
+ const std::vector<FilePath>::iterator end = key_files.end();
+ for (std::vector<FilePath>::iterator scan = key_files.begin();
+ scan != end; ++scan) {
+ *scan = next_version.Append(*scan);
+ }
+
+ VLOG(1) << "Deleting directory: " << next_version.value();
+
+ scoped_ptr<WorkItem> item(
+ WorkItem::CreateDeleteTreeWorkItem(next_version, key_files));
+ if (!item->Do())
+ item->Rollback();
+ }
+
+ next_version = version_enum.Next();
+ }
+}
+
+void InstallerState::AddComDllList(std::vector<FilePath>* com_dll_list) const {
+ std::for_each(products_.begin(), products_.end(),
+ std::bind2nd(std::mem_fun(&Product::AddComDllList),
+ com_dll_list));
+}
+
+bool InstallerState::SetChannelFlags(bool set,
+ ChannelInfo* channel_info) const {
+ bool modified = false;
+
+ // We don't have access to lambdas yet, but we can sure fake it!.
+ struct SetChannelFlagsFunc
+ : public std::unary_function<const Product*, void> {
+ public:
+ SetChannelFlagsFunc(bool set, ChannelInfo* channel_info, bool* modified)
+ : channel_info_(channel_info), modified_(modified), set_(set) {}
+ result_type operator()(argument_type product) const {
+ *modified_ |= product->SetChannelFlags(set_, channel_info_);
+ }
+ private:
+ ChannelInfo* channel_info_;
+ bool* modified_;
+ bool set_;
+ };
+
+ std::for_each(products_.begin(), products_.end(),
+ SetChannelFlagsFunc(set, channel_info, &modified));
+ 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...
+}
+
} // namespace installer

Powered by Google App Engine
This is Rietveld 408576698