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 |