| 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,275 @@
|
| return true;
|
| }
|
|
|
| -InstallerState::InstallerState() : operation_(UNINITIALIZED) {
|
| +InstallerState::InstallerState()
|
| + : operation_(UNINITIALIZED),
|
| + level_(UNKNOWN_LEVEL),
|
| + package_type_(UNKNOWN_PACKAGE_TYPE),
|
| + root_key_(NULL),
|
| + msi_(false),
|
| + verbose_logging_(false) {
|
| }
|
|
|
| -void InstallerState::Initialize(const MasterPreferences& prefs,
|
| +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_))
|
| + 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) {
|
| + 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_ = product->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);
|
| + 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));
|
| + 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)) {
|
| + 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;
|
| +}
|
| +
|
| } // namespace installer
|
|
|