1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/test/mini_installer_test/installer_path_provider.h" 6 7 #include <algorithm> 8 9 #include "base/command_line.h" 10 #include "base/file_util.h" 11 #include "base/files/file_enumerator.h" 12 #include "base/path_service.h" 13 #include "base/strings/string_util.h" 14 #include "base/strings/stringprintf.h" 15 #include "chrome/test/mini_installer_test/installer_test_util.h" 16 #include "chrome/test/mini_installer_test/mini_installer_test_constants.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 namespace { 20 21 struct FilePathInfo { 22 base::FileEnumerator::FileInfo info; 23 base::FilePath path; 24 }; 25 26 bool CompareDate(const FilePathInfo& a, const FilePathInfo& b) { 27 return a.info.GetLastModifiedTime() > b.info.GetLastModifiedTime(); 28 } 29 30 // Get list of file |type| matching |pattern| in |root|. 31 // The list is sorted in last modified date order. 32 // Return true if files/directories are found. 33 bool FindMatchingFiles(const base::FilePath& root, 34 const std::string& pattern, 35 base::FileEnumerator::FileType type, 36 std::vector<base::FilePath>* paths) { 37 base::FileEnumerator files(root, false, type, 38 base::FilePath().AppendASCII(pattern).value()); 39 std::vector<FilePathInfo> matches; 40 for (base::FilePath current = files.Next(); !current.empty(); 41 current = files.Next()) { 42 FilePathInfo entry; 43 entry.info = files.GetInfo(); 44 entry.path = current; 45 matches.push_back(entry); 46 } 47 48 if (matches.empty()) 49 return false; 50 51 std::sort(matches.begin(), matches.end(), CompareDate); 52 std::vector<FilePathInfo>::iterator current; 53 for (current = matches.begin(); current != matches.end(); ++current) { 54 paths->push_back(current->path); 55 } 56 return true; 57 } 58 59 bool FindNewestMatchingFile(const base::FilePath& root, 60 const std::string& pattern, 61 base::FileEnumerator::FileType type, 62 base::FilePath* path) { 63 std::vector<base::FilePath> paths; 64 if (FindMatchingFiles(root, pattern, type, &paths)) { 65 *path = paths[0]; 66 return true; 67 } 68 return false; 69 } 70 71 } // namespace 72 73 namespace installer_test { 74 75 InstallerPathProvider::InstallerPathProvider() { 76 base::FilePath full_installer, previous_installer; 77 if (!GetFullInstaller(&full_installer) || 78 !GetPreviousInstaller(&previous_installer)) 79 return; 80 current_build_ = 81 full_installer.DirName().DirName().BaseName().MaybeAsASCII(); 82 previous_build_ = 83 previous_installer.DirName().DirName().BaseName().MaybeAsASCII(); 84 } 85 86 InstallerPathProvider::InstallerPathProvider( 87 const std::string& build_under_test) : current_build_(build_under_test) { 88 base::FilePath full_installer, previous_installer; 89 if (!GetFullInstaller(&full_installer) || 90 !GetPreviousInstaller(&previous_installer)) 91 return; 92 previous_build_ = 93 previous_installer.DirName().DirName().BaseName().MaybeAsASCII(); 94 } 95 96 InstallerPathProvider::~InstallerPathProvider() {} 97 98 bool InstallerPathProvider::GetFullInstaller(base::FilePath* path) { 99 std::string full_installer_pattern("*_chrome_installer*"); 100 return GetInstaller(full_installer_pattern, path); 101 } 102 103 bool InstallerPathProvider::GetDiffInstaller(base::FilePath* path) { 104 std::string diff_installer_pattern("*_from_*"); 105 return GetInstaller(diff_installer_pattern, path); 106 } 107 108 bool InstallerPathProvider::GetMiniInstaller(base::FilePath* path) { 109 // Use local copy of installer, else fall back to filer. 110 base::FilePath mini_installer = PathFromExeDir( 111 mini_installer_constants::kChromeMiniInstallerExecutable); 112 if (base::PathExists(mini_installer)) { 113 *path = mini_installer; 114 return true; 115 } 116 std::string mini_installer_pattern("mini_installer.exe"); 117 return GetInstaller(mini_installer_pattern, path); 118 } 119 120 bool InstallerPathProvider::GetPreviousInstaller(base::FilePath* path) { 121 std::string diff_installer_pattern("*_from_*"); 122 std::string full_installer_pattern("*_chrome_installer*"); 123 base::FilePath diff_installer; 124 if (!GetInstaller(diff_installer_pattern, &diff_installer)) 125 return false; 126 127 base::FilePath previous_installer; 128 std::vector<std::string> tokenized_name; 129 Tokenize(diff_installer.BaseName().MaybeAsASCII(), 130 "_", &tokenized_name); 131 std::string build_pattern = base::StringPrintf( 132 "*%s", tokenized_name[2].c_str()); 133 std::vector<base::FilePath> previous_build; 134 if (FindMatchingFiles(diff_installer.DirName().DirName().DirName(), 135 build_pattern, base::FileEnumerator::DIRECTORIES, 136 &previous_build)) { 137 base::FilePath windir = previous_build.at(0).Append( 138 mini_installer_constants::kWinFolder); 139 FindNewestMatchingFile(windir, full_installer_pattern, 140 base::FileEnumerator::FILES, &previous_installer); 141 } 142 143 if (previous_installer.empty()) 144 return false; 145 *path = previous_installer; 146 return true; 147 } 148 149 bool InstallerPathProvider::GetStandaloneInstaller(base::FilePath* path) { 150 // Get standalone installer. 151 base::FilePath standalone_installer( 152 mini_installer_constants::kChromeStandAloneInstallerLocation); 153 // Get the file name. 154 std::vector<std::string> tokenized_build_number; 155 if (current_build_.empty()) 156 return false; 157 Tokenize(current_build_, ".", &tokenized_build_number); 158 std::string standalone_installer_filename = base::StringPrintf( 159 "%s%s_%s.exe", 160 base::FilePath(mini_installer_constants::kUntaggedInstallerPattern) 161 .MaybeAsASCII().c_str(), 162 tokenized_build_number[2].c_str(), 163 tokenized_build_number[3].c_str()); 164 standalone_installer = standalone_installer.AppendASCII(current_build_) 165 .Append(mini_installer_constants::kWinFolder) 166 .AppendASCII(standalone_installer_filename); 167 *path = standalone_installer; 168 return base::PathExists(standalone_installer); 169 } 170 171 bool InstallerPathProvider::GetSignedStandaloneInstaller(base::FilePath* path) { 172 base::FilePath standalone_installer; 173 if (!GetStandaloneInstaller(&standalone_installer)) 174 return false; 175 base::FilePath tagged_installer = PathFromExeDir( 176 mini_installer_constants::kStandaloneInstaller); 177 CommandLine sign_command = CommandLine::FromString( 178 base::StringPrintf(L"%ls %ls %ls %ls", 179 mini_installer_constants::kChromeApplyTagExe, 180 standalone_installer.value().c_str(), 181 tagged_installer.value().c_str(), 182 mini_installer_constants::kChromeApplyTagParameters)); 183 184 if (!installer_test::RunAndWaitForCommandToFinish(sign_command)) 185 return false; 186 187 *path = PathFromExeDir(mini_installer_constants::kStandaloneInstaller); 188 return true; 189 } 190 191 base::FilePath InstallerPathProvider::PathFromExeDir( 192 const base::FilePath::StringType& name) { 193 base::FilePath path; 194 PathService::Get(base::DIR_EXE, &path); 195 path = path.Append(name); 196 return path; 197 } 198 199 bool InstallerPathProvider::GetInstaller(const std::string& pattern, 200 base::FilePath* path) { 201 base::FilePath installer; 202 // Search filer for installer binary. 203 base::FilePath root(mini_installer_constants::kChromeInstallersLocation); 204 std::vector<base::FilePath> paths; 205 if (!FindMatchingFiles(root, current_build_, 206 base::FileEnumerator::DIRECTORIES, &paths)) { 207 return false; 208 } 209 210 std::vector<base::FilePath>::const_iterator dir; 211 for (dir = paths.begin(); dir != paths.end(); ++dir) { 212 base::FilePath windir = dir->Append( 213 mini_installer_constants::kWinFolder); 214 if (FindNewestMatchingFile(windir, pattern, base::FileEnumerator::FILES, 215 &installer)) { 216 break; 217 } 218 } 219 220 if (installer.empty()) { 221 LOG(WARNING) << "Failed to find installer with pattern: " << pattern; 222 return false; 223 } 224 225 *path = installer; 226 return true; 227 } 228 229 std::string InstallerPathProvider::GetCurrentBuild() { 230 return current_build_; 231 } 232 233 std::string InstallerPathProvider::GetPreviousBuild() { 234 return previous_build_; 235 } 236 237 } // namespace 238