Chromium Code Reviews| Index: chrome/installer/test/alternate_version_generator.cc |
| =================================================================== |
| --- chrome/installer/test/alternate_version_generator.cc (revision 0) |
| +++ chrome/installer/test/alternate_version_generator.cc (revision 0) |
| @@ -0,0 +1,568 @@ |
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +// The file contains the implementation of the mini_installer re-versioner. |
| +// The main function (GenerateNextVersion) does the following in a temp dir: |
| +// - Extracts and unpacks setup.exe and the Chrome-bin folder from |
| +// mini_installer.exe. |
| +// - Inspects setup.exe to determine the current version. |
| +// - Runs through all .dll and .exe files: |
| +// - Replacing all occurrences of the Unicode version string in the files' |
| +// resources with the updated string. |
| +// - For all resources in which the string substitution is made, the binary |
| +// form of the version is also replaced. |
| +// - Re-packs setup.exe and Chrome-bin. |
| +// - Inserts them into the target mini_installer.exe. |
| + |
| +#include "chrome/installer/test/alternate_version_generator.h" |
| + |
| +#include <windows.h> |
| + |
| +#include <algorithm> |
| +#include <sstream> |
| +#include <limits> |
| +#include <utility> |
| +#include <vector> |
| + |
| +#include "base/basictypes.h" |
| +#include "base/file_path.h" |
| +#include "base/file_util.h" |
| +#include "base/logging.h" |
| +#include "base/platform_file.h" |
| +#include "base/win/pe_image.h" |
| +#include "base/win/scoped_handle.h" |
| +#include "chrome/installer/test/pe_image_resources.h" |
| +#include "chrome/installer/test/resource_loader.h" |
| +#include "chrome/installer/test/resource_updater.h" |
| +#include "chrome/installer/util/lzma_util.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +// Notes: |
|
robertshield
2010/11/19 20:56:42
Could we move this Notes section up to the comment
grt (UTC plus 2)
2010/11/22 17:53:29
I've deleted the notes since they are no longer re
|
| +// Modifying a resource may mean moving around the contents of the .rsrc |
| +// section, which would mean adjusting all resources that follow as well as |
| +// potentially all sections that follow. |
| + |
| +namespace { |
| + |
| +const wchar_t k7zaPath[] = |
| + L"..\\..\\third_party\\lzma_sdk\\Executable\\7za.exe"; |
|
robertshield
2010/11/19 20:56:42
I'm uneasy about the "..\\"s, I'd prefer if the st
grt (UTC plus 2)
2010/11/22 17:53:29
I've changed these a bit. See my response to your
|
| +const wchar_t kB7[] = L"B7"; |
| +const wchar_t kBl[] = L"BL"; |
| +const wchar_t kChrome7z[] = L"chrome.7z"; |
| +const wchar_t kChromeBin[] = L"Chrome-bin"; |
| +const wchar_t kChromePacked7z[] = L"chrome.packed.7z"; |
| +const wchar_t kExe[] = L"exe"; |
| +const wchar_t kExpandExe[] = L"expand.exe"; |
| +const wchar_t kExtDll[] = L".dll"; |
| +const wchar_t kExtExe[] = L".exe"; |
| +const wchar_t kMakeCab[] = L"makecab.exe"; |
| +const wchar_t kSetupEx_[] = L"setup.ex_"; |
| +const wchar_t kSetupExe[] = L"setup.exe"; |
| +const wchar_t kTempDirPrefix[] = L"mini_installer_test_temp"; |
| + |
| +// A helper class for creating and cleaning a temporary directory. A temporary |
| +// directory is created in Initialize and destroyed (along with all of its |
| +// contents) when the guard instance is destroyed. |
| +class ScopedTempDirectory { |
| + public: |
| + ScopedTempDirectory() { } |
| + ~ScopedTempDirectory() { |
| + if (!directory_.empty() && !file_util::Delete(directory_, true)) { |
| + LOG(DFATAL) << "Failed deleting temporary directory \"" |
| + << directory_.value() << "\""; |
| + } |
| + } |
| + // Creates a temporary directory. |
| + bool Initialize() { |
| + DCHECK(directory_.empty()); |
| + if (!file_util::CreateNewTempDirectory(&kTempDirPrefix[0], &directory_)) { |
| + LOG(DFATAL) << "Failed creating temporary directory."; |
| + return false; |
| + } |
| + return true; |
| + } |
| + const FilePath& directory() const { |
| + DCHECK(!directory_.empty()); |
| + return directory_; |
| + } |
| + private: |
| + FilePath directory_; |
| + DISALLOW_COPY_AND_ASSIGN(ScopedTempDirectory); |
| +}; // class ScopedTempDirectory |
| + |
| +// A helper class for manipulating a Chrome product version. |
| +class ChromeVersion { |
| + public: |
| + static ChromeVersion FromHighLow(DWORD high, DWORD low) { |
| + return ChromeVersion(static_cast<ULONGLONG>(high) << 32 | |
| + static_cast<ULONGLONG>(low)); |
| + } |
| + ChromeVersion() { } |
| + explicit ChromeVersion(ULONGLONG value) : version_(value) { } |
| + WORD major() const { return static_cast<WORD>(version_ >> 48); } |
| + WORD minor() const { return static_cast<WORD>(version_ >> 32); } |
| + WORD build() const { return static_cast<WORD>(version_ >> 16); } |
| + WORD patch() const { return static_cast<WORD>(version_); } |
| + DWORD high() const { return static_cast<DWORD>(version_ >> 32); } |
| + DWORD low() const { return static_cast<DWORD>(version_); } |
| + ULONGLONG value() const { return version_; } |
| + void set_value(ULONGLONG value) { version_ = value; } |
| + std::wstring ToString() const; |
| + private: |
| + ULONGLONG version_; |
| +}; // class ChromeVersion |
| + |
| +std::wstring ChromeVersion::ToString() const { |
| + wchar_t buffer[24]; |
| + int string_len = |
| + swprintf_s(&buffer[0], arraysize(buffer), L"%hu.%hu.%hu.%hu", |
| + major(), minor(), build(), patch()); |
| + DCHECK_NE(-1, string_len); |
| + DCHECK_GT(static_cast<int>(arraysize(buffer)), string_len); |
| + return std::wstring(&buffer[0], string_len); |
| +} |
| + |
| +// A read/write mapping of a file. |
| +// Note: base::MemoryMappedFile is not used because it doesn't support |
| +// read/write mappings. Adding such support across all platforms for this |
| +// Windows-only test code seems like overkill. |
| +class MappedFile { |
| + public: |
| + MappedFile() : size_(), mapping_(), view_() { } |
| + ~MappedFile(); |
| + bool Initialize(base::PlatformFile file); |
| + LPVOID data() const { return view_; } |
|
tommi (sloooow) - chröme
2010/11/19 20:14:38
I think we prefer void* to LPVOID like defs (excep
grt (UTC plus 2)
2010/11/22 17:53:29
Done.
|
| + size_t size() const { return size_; } |
| + private: |
| + size_t size_; |
| + HANDLE mapping_; |
| + LPVOID view_; |
| + DISALLOW_COPY_AND_ASSIGN(MappedFile); |
| +}; // class MappedFile |
| + |
| +MappedFile::~MappedFile() { |
| + if (view_ != NULL) { |
| + EXPECT_NE(0, UnmapViewOfFile(view_)); |
| + } |
| + if (mapping_ != NULL) { |
| + EXPECT_NE(0, CloseHandle(mapping_)); |
| + } |
| +} |
| + |
| +bool MappedFile::Initialize(base::PlatformFile file) { |
| + DCHECK(mapping_ == NULL); |
| + bool result = false; |
| + base::PlatformFileInfo file_info; |
| + |
| + if (base::GetPlatformFileInfo(file, &file_info)) { |
| + if (file_info.size <= |
| + static_cast<int64>(std::numeric_limits<size_t>::max())) { |
| + mapping_ = CreateFileMapping(file, NULL, PAGE_READWRITE, 0, |
| + static_cast<DWORD>(file_info.size), NULL); |
| + if (mapping_ != NULL) { |
| + view_ = MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0, |
| + static_cast<size_t>(file_info.size)); |
| + if (view_ != NULL) { |
| + result = true; |
| + } else { |
| + PLOG(DFATAL) << "MapViewOfFile failed"; |
| + } |
| + } else { |
| + PLOG(DFATAL) << "CreateFileMapping failed"; |
| + } |
| + } else { |
| + LOG(DFATAL) << "Files larger than " << std::numeric_limits<size_t>::max() |
| + << " are not supported."; |
| + } |
| + } else { |
| + PLOG(DFATAL) << "GetPlatformFileInfo failed"; |
| + } |
| + return result; |
| +} |
| + |
| +// Calls CreateProcess with good default parameters and waits for the process |
| +// to terminate returning the process exit code. |
| +bool RunProcessAndWait(const wchar_t* exe_path, const std::wstring& cmdline, |
|
tommi (sloooow) - chröme
2010/11/19 20:14:38
Would it make sense to use the CommandLine class h
grt (UTC plus 2)
2010/11/22 17:53:29
I'm not sure. It looks to me like CommandLine::Ap
tommi (sloooow) - chröme
2010/11/22 19:43:42
agreed. keep as is.
|
| + int* exit_code) { |
|
robertshield
2010/11/19 20:56:42
can't you use base::LaunchApp() in process_utils.h
grt (UTC plus 2)
2010/11/22 17:53:29
I thought it would be nice to use CREATE_NO_WINDOW
robertshield
2010/11/22 19:59:08
Ideally there would be a --silent argument that co
grt (UTC plus 2)
2010/11/22 20:49:23
Done (although no such luck finding flags for the
|
| + std::vector<wchar_t> cmd_line(cmdline.c_str(), |
| + cmdline.c_str() + cmdline.size() + 1); |
| + STARTUPINFOW si = {sizeof(si)}; |
| + PROCESS_INFORMATION pi = {0}; |
| + if (!CreateProcess(exe_path, &cmd_line[0], NULL, NULL, FALSE, |
| + CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { |
| + PLOG(DFATAL) << "CreateProcess failed with command line: \"" << cmdline |
| + << "\""; |
| + return false; |
| + } |
| + |
| + CloseHandle(pi.hThread); |
| + bool result = true; |
| + DWORD wr = WaitForSingleObject(pi.hProcess, INFINITE); |
| + if (wr == WAIT_OBJECT_0) { |
| + if (exit_code) { |
| + if (!GetExitCodeProcess(pi.hProcess, |
| + reinterpret_cast<DWORD*>(exit_code))) { |
| + PLOG(DFATAL) << "Failed getting the exit code for \"" |
| + << &cmd_line[0] << "\"."; |
| + result = false; |
| + } |
| + } |
|
tommi (sloooow) - chröme
2010/11/19 20:14:38
maybe add a DCHECK(exit_code != STILL_RUNNING) if
grt (UTC plus 2)
2010/11/22 17:53:29
Done.
|
| + } else { |
| + if (wr == WAIT_FAILED) { |
| + PLOG(DFATAL) << "Failed while waiting for \"" << &cmd_line[0] |
| + << "\" to exit."; |
| + } else { |
| + LOG(DFATAL) << "Received result " << wr << " while waiting for \"" |
| + << &cmd_line[0] << "\" to exit."; |
| + } |
| + result = false; |
| + } |
| + |
| + CloseHandle(pi.hProcess); |
| + return result; |
| +} |
| + |
| +// Retrieves the version number of setup.exe in |work_dir| from its version |
| +// resource, placing the value in |version|. Returns true on success. |
| +bool GetSetupExeVersion(const FilePath& work_dir, ChromeVersion* version) { |
| + DCHECK(version); |
| + bool result = false; |
| + upgrade_test::ResourceLoader setup; |
| + std::pair<const uint8*, DWORD> version_info_data; |
| + |
| + if (setup.Initialize(work_dir.Append(&kSetupExe[0])) && |
| + setup.Load(VS_VERSION_INFO, reinterpret_cast<WORD>(RT_VERSION), |
| + &version_info_data)) { |
| + const VS_FIXEDFILEINFO* fixed_file_info; |
| + UINT ver_info_len; |
| + if (VerQueryValue(version_info_data.first, L"\\", |
| + reinterpret_cast<void**>( |
| + const_cast<VS_FIXEDFILEINFO**>(&fixed_file_info)), |
| + &ver_info_len) != 0) { |
| + DCHECK_EQ(sizeof(VS_FIXEDFILEINFO), static_cast<size_t>(ver_info_len)); |
| + *version = ChromeVersion::FromHighLow(fixed_file_info->dwFileVersionMS, |
| + fixed_file_info->dwFileVersionLS); |
| + result = true; |
| + } else { |
| + LOG(DFATAL) << "VerQueryValue failed to retrieve VS_FIXEDFILEINFO"; |
| + } |
| + } |
| + |
| + return result; |
| +} |
| + |
| +// Replace all occurrences in the sequence [|dest_first|, |dest_last) that |
| +// equals [|src_first|, |src_last) with the sequence at |replacement_first| of |
| +// the same length. Returns true on success. If non-NULL, |replacements_made| |
| +// is set to true/false accordingly. |
| +bool ReplaceAll(uint8* dest_first, uint8* dest_last, |
| + const uint8* src_first, const uint8* src_last, |
| + const uint8* replacement_first, bool* replacements_made) { |
| + bool result = true; |
| + bool changed = false; |
| + do { |
| + dest_first = std::search(dest_first, dest_last, src_first, src_last); |
| + if (dest_first == dest_last) { |
| + break; |
| + } |
| + changed = true; |
| + if (memcpy_s(dest_first, dest_last - dest_first, |
| + replacement_first, src_last - src_first) != 0) { |
| + result = false; |
| + break; |
| + } |
| + dest_first += (src_last - src_first); |
| + } while (true); |
| + |
| + if (replacements_made != NULL) { |
| + *replacements_made = changed; |
| + } |
| + |
| + return result; |
| +} |
| + |
| +// A context structure in support of our EnumResource_Fn function. |
| +struct VisitResourceContext { |
| + ChromeVersion current_version; |
| + std::wstring current_version_str; |
| + ChromeVersion new_version; |
| + std::wstring new_version_str; |
| +}; // struct VisitResourceContext |
| + |
| +// Replaces the old version with the new in a resource. A first pass is made to |
| +// replace the string form (e.g., "9.0.584.0"). If any replacements are made, a |
| +// second pass is made to replace the binary form (e.g., 0x0000024800000009). |
| +void VisitResource(const upgrade_test::EntryPath& path, |
| + uint8* data, DWORD size, DWORD code_page, |
| + uintptr_t context) { |
| + VisitResourceContext& ctx = *reinterpret_cast<VisitResourceContext*>(context); |
| + |
| + // Replace all occurrences of current_version_str with new_version_str |
| + bool changing_version = false; |
| + if (ReplaceAll( |
| + data, data + size, |
|
robertshield
2010/11/19 20:56:42
for readability, these two arguments should be on
grt (UTC plus 2)
2010/11/22 17:53:29
Done.
|
| + reinterpret_cast<const uint8*>(ctx.current_version_str.c_str()), |
| + reinterpret_cast<const uint8*>(ctx.current_version_str.c_str() + |
| + ctx.current_version_str.size() + 1), |
| + reinterpret_cast<const uint8*>(ctx.new_version_str.c_str()), |
| + &changing_version) && |
| + changing_version) { |
| + // Replace all occurrences of current_version with new_version |
| + struct VersionPair { |
| + DWORD high; |
| + DWORD low; |
| + }; |
| + VersionPair cur_ver = { |
| + ctx.current_version.high(), ctx.current_version.low() |
| + }; |
| + VersionPair new_ver = { |
| + ctx.new_version.high(), ctx.new_version.low() |
| + }; |
| + ReplaceAll(data, data + size, reinterpret_cast<const uint8*>(&cur_ver), |
| + reinterpret_cast<const uint8*>(&cur_ver) + sizeof(cur_ver), |
| + reinterpret_cast<const uint8*>(&new_ver), NULL); |
| + } |
| +} |
| + |
| +// Updates the version strings and numbers in all of |image_file|'s resources. |
| +bool UpdateVersionIfMatch(const FilePath& image_file, |
| + VisitResourceContext* context) { |
| + bool result = false; |
| + base::win::ScopedHandle image_handle(base::CreatePlatformFile( |
| + image_file, |
| + (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ | |
| + base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_READ | |
| + base::PLATFORM_FILE_EXCLUSIVE_WRITE), NULL, NULL)); |
| + if (image_handle.Get() != INVALID_HANDLE_VALUE) { |
| + MappedFile image_mapping; |
| + if (image_mapping.Initialize(image_handle)) { |
| + base::win::PEImageAsData image( |
| + reinterpret_cast<HMODULE>(image_mapping.data())); |
| + // PEImage class does not support other-architecture images. |
| + if (image.GetNTHeaders()->OptionalHeader.Magic == |
| + IMAGE_NT_OPTIONAL_HDR_MAGIC) { |
| + result = upgrade_test::EnumResources( |
| + image, &VisitResource, reinterpret_cast<uintptr_t>(context)); |
| + } else { |
| + result = true; |
| + } |
| + } |
| + } else { |
| + PLOG(DFATAL) << "Failed to open \"" << image_file.value() << "\""; |
| + } |
| + return result; |
| +} |
| + |
| +// Bumps the version of all .exe and .dll files in |work_dir|. |
|
robertshield
2010/11/19 20:56:42
update comment to reference version bumping on the
grt (UTC plus 2)
2010/11/22 17:53:29
Done.
|
| +bool ApplyNextVersion(const FilePath& work_dir) { |
| + VisitResourceContext ctx; |
| + if (!GetSetupExeVersion(work_dir, &ctx.current_version)) { |
| + return false; |
| + } |
| + ctx.current_version_str = ctx.current_version.ToString(); |
| + |
| + // Figure out a future version with the same string length as this one by |
| + // incrementing each component. |
| + ULONGLONG incrementer = 1; |
| + |
| + do { |
| + if (incrementer == 0) { |
| + LOG(DFATAL) << "Improbable version composed of only 9s and/or USHRT_MAX"; |
| + return false; |
| + } |
| + ctx.new_version.set_value(ctx.current_version.value() + incrementer); |
| + ctx.new_version_str = ctx.new_version.ToString(); |
| + incrementer <<= 16; |
| + } while (ctx.new_version_str.size() != ctx.current_version_str.size()); |
| + |
| + // Modify all .dll and .exe files with the current version. |
| + bool doing_great = true; |
|
tommi (sloooow) - chröme
2010/11/19 20:14:38
/like
grt (UTC plus 2)
2010/11/22 17:53:29
Done. :-)
|
| + file_util::FileEnumerator all_files(work_dir, true, |
| + file_util::FileEnumerator::FILES); |
| + do { |
| + FilePath file = all_files.Next(); |
| + if (file.empty()) { |
| + break; |
| + } |
| + std::wstring extension = file.Extension(); |
| + if (extension == &kExtExe[0] || extension == &kExtDll[0]) { |
| + doing_great = UpdateVersionIfMatch(file, &ctx); |
| + } |
| + } while (doing_great); |
| + |
| + // Change the versioned directory. |
| + FilePath chrome_bin = work_dir.Append(&kChromeBin[0]); |
| + doing_great = file_util::Move(chrome_bin.Append(ctx.current_version_str), |
| + chrome_bin.Append(ctx.new_version_str)); |
| + |
| + return doing_great; |
| +} |
| + |
| +bool CreateArchive(const FilePath& output_file, const FilePath& input_path, |
| + int compression_level) { |
| + DCHECK(compression_level == 0 || |
| + compression_level >= 1 && compression_level <= 9 && |
| + (compression_level & 0x01) != 0); |
| + |
| + std::wstring command_line(1, L'"'); |
| + command_line |
|
robertshield
2010/11/19 20:56:42
since this is a relative path, this code assumes i
grt (UTC plus 2)
2010/11/22 17:53:29
I've done three things:
1) Documented.
2) Made the
|
| + .append(&k7zaPath[0]) |
| + .append(L"\" a -t7z \"") |
| + .append(output_file.value()) |
| + .append(L"\" \"") |
| + .append(input_path.value()) |
| + .append(L"\" -mx") |
| + .append(1, L'0' + compression_level); |
| + int exit_code; |
| + if (!RunProcessAndWait(NULL, command_line, &exit_code)) |
| + return false; |
| + if (exit_code != 0) { |
| + LOG(DFATAL) << &k7zaPath[0] << " exited with code " << exit_code |
| + << " while creating " << output_file.value(); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +namespace upgrade_test { |
| + |
| +bool GenerateNextVersion(const FilePath& original_installer_path, |
| + const FilePath& target_path) { |
| + // Create a temporary directory in which we'll do our work. |
| + ScopedTempDirectory work_dir; |
| + if (!work_dir.Initialize()) |
| + return false; |
| + |
| + // Copy the original mini_installer. |
| + FilePath mini_installer = |
| + work_dir.directory().Append(original_installer_path.BaseName()); |
|
tommi (sloooow) - chröme
2010/11/19 20:14:38
indent
grt (UTC plus 2)
2010/11/22 17:53:29
Done.
|
| + if (!file_util::CopyFile(original_installer_path, mini_installer)) { |
| + LOG(DFATAL) << "Failed copying \"" << original_installer_path.value() |
| + << "\" to \"" << mini_installer.value() << "\""; |
| + return false; |
| + } |
| + |
| + FilePath setup_ex_ = work_dir.directory().Append(&kSetupEx_[0]); |
| + FilePath chrome_packed_7z = work_dir.directory().Append(&kChromePacked7z[0]); |
| + // Load the original file and extract setup.ex_ and chrome.packed.7z |
| + { |
| + ResourceLoader resource_loader; |
| + std::pair<const uint8*, DWORD> resource_data; |
| + |
| + if (!resource_loader.Initialize(mini_installer)) |
| + return false; |
| + |
| + // Write out setup.ex_ |
| + if (!resource_loader.Load(&kSetupEx_[0], &kBl[0], &resource_data)) |
| + return false; |
| + int written = |
| + file_util::WriteFile(setup_ex_, |
| + reinterpret_cast<const char*>(resource_data.first), |
| + static_cast<int>(resource_data.second)); |
| + if (written != resource_data.second) { |
| + LOG(DFATAL) << "Failed writing \"" << setup_ex_.value() << "\""; |
| + return false; |
| + } |
| + |
| + // Write out chrome.packed.7z |
| + if (!resource_loader.Load(&kChromePacked7z[0], &kB7[0], &resource_data)) |
| + return false; |
| + written = |
| + file_util::WriteFile(chrome_packed_7z, |
| + reinterpret_cast<const char*>(resource_data.first), |
| + static_cast<int>(resource_data.second)); |
| + if (written != resource_data.second) { |
| + LOG(DFATAL) << "Failed writing \"" << chrome_packed_7z.value() << "\""; |
| + return false; |
| + } |
| + } |
| + |
| + // Expand setup.ex_ |
| + FilePath setup_exe = setup_ex_.ReplaceExtension(&kExe[0]); |
| + std::wstring command_line; |
| + command_line.append(1, L'"') |
| + .append(&kExpandExe[0]) |
| + .append(L"\" \"") |
| + .append(setup_ex_.value()) |
| + .append(L"\" \"") |
| + .append(setup_exe.value()) |
| + .append(1, L'\"'); |
| + int exit_code; |
| + if (!RunProcessAndWait(NULL, command_line, &exit_code)) |
| + return false; |
| + if (exit_code != 0) { |
| + LOG(DFATAL) << &kExpandExe[0] << " exited with code " << exit_code; |
| + return false; |
| + } |
| + |
| + // Unpack chrome.packed.7z |
| + std::wstring chrome_7z_name; |
| + if (LzmaUtil::UnPackArchive(chrome_packed_7z.value(), |
| + work_dir.directory().value(), |
| + &chrome_7z_name) != NO_ERROR) { |
| + LOG(DFATAL) << "Failed unpacking \"" << chrome_packed_7z.value() << "\""; |
| + return false; |
| + } |
| + |
| + // Unpack chrome.7z |
| + if (LzmaUtil::UnPackArchive(chrome_7z_name, work_dir.directory().value(), |
| + NULL) != NO_ERROR) { |
| + LOG(DFATAL) << "Failed unpacking \"" << chrome_7z_name << "\""; |
| + return false; |
| + } |
| + |
| + // Get rid of intermediate files |
| + FilePath chrome_7z(chrome_7z_name); |
| + if (!file_util::Delete(chrome_7z, false) || |
| + !file_util::Delete(chrome_packed_7z, false) || |
| + !file_util::Delete(setup_ex_, false)) { |
| + LOG(DFATAL) << "Failed deleting intermediate files"; |
| + return false; |
| + } |
| + |
| + // Increment the version in all files. |
| + ApplyNextVersion(work_dir.directory()); |
| + |
| + // Pack up files into chrome.7z |
| + if (!CreateArchive(chrome_7z, work_dir.directory().Append(&kChromeBin[0]), 0)) |
| + return false; |
| + |
| + // Compress chrome.7z into chrome.packed.7z |
| + if (!CreateArchive(chrome_packed_7z, chrome_7z, 9)) |
| + return false; |
| + |
| + // Compress setup.exe into setup.ex_ |
| + command_line.assign(1, L'"') |
| + .append(&kMakeCab[0]) |
| + .append(L"\" /D CompressionType=LZX /V1 /L \"") |
| + .append(work_dir.directory().value()) |
| + .append(L"\" \"") |
| + .append(setup_exe.value()); |
| + if (!RunProcessAndWait(NULL, command_line, &exit_code)) |
| + return false; |
| + if (exit_code != 0) { |
| + LOG(DFATAL) << &kMakeCab[0] << " exited with code " << exit_code; |
| + return false; |
| + } |
| + |
| + // Replace the mini_installer's setup.ex_ and chrome.packed.7z resources. |
| + ResourceUpdater updater; |
| + if (!updater.Initialize(mini_installer) || |
| + !updater.Update(&kSetupEx_[0], &kBl[0], |
| + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), |
| + setup_ex_) || |
| + !updater.Update(&kChromePacked7z[0], &kB7[0], |
| + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), |
| + chrome_packed_7z) || |
| + !updater.Commit()) { |
| + return false; |
| + } |
| + |
| + // Finally, move the updated mini_installer into place. |
| + return file_util::Move(mini_installer, target_path); |
| +} |
| + |
| +} // namespace upgrade_test |
| Property changes on: chrome\installer\test\alternate_version_generator.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |