From 2658f1235dd270840c73eae18ce155b5d6554386 Mon Sep 17 00:00:00 2001 From: Robert Knight Date: Fri, 30 Aug 2013 15:33:46 +0100 Subject: [PATCH] Fix update installer test on Windows * Remove the dependency on Cygwin being installed along with zip.exe at a specific location. Add a small cross-platform tool in zip.cpp which creates a zip file using the contents of a given directory. This also removes the need for passing different arguments to 'zip' depending on the platform. * Fix StringUtils::endsWith() * Fix UpdateDialogWin32::quit(), when called on a background thread it had no effect. Post the WM_QUIT message to the main thread. --- src/CMakeLists.txt | 4 +++ src/FileUtils.cpp | 43 +++++++++++++++++++++++++ src/FileUtils.h | 5 +++ src/StringUtils.h | 2 +- src/UpdateDialogWin32.cpp | 2 +- src/tests/test-update.rb | 26 ++------------- src/zip.cpp | 68 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 25 deletions(-) create mode 100644 src/zip.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6adb20..af79df5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,3 +133,7 @@ endif() install(TARGETS updater RUNTIME DESTINATION bin) +add_executable(zip-tool zip.cpp) +target_link_libraries(zip-tool updatershared) + + diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 8528b8a..ab06f33 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -11,6 +11,7 @@ #include #include +#include "minizip/zip.h" #include "minizip/unzip.h" #ifdef PLATFORM_UNIX @@ -145,6 +146,37 @@ void FileUtils::moveFile(const char* src, const char* dest) throw (IOException) #endif } +void FileUtils::addToZip(const char* archivePath, const char* path, const char* content, int length) throw (IOException) +{ + int result = ZIP_OK; + + int appendMode = fileExists(archivePath) ? APPEND_STATUS_ADDINZIP : APPEND_STATUS_CREATE; + + zipFile archive = zipOpen(archivePath, appendMode); + result = zipOpenNewFileInZip(archive, path, 0 /* file attributes */, 0 /* extra field */, 0 /* extra field size */, + 0/* global extra field */, 0 /* global extra field size */, 0 /* comment */, Z_DEFLATED /* method */, + Z_DEFAULT_COMPRESSION /* level */); + if (result != ZIP_OK) + { + throw IOException("Unable to add new file to zip archive"); + } + result = zipWriteInFileInZip(archive, content, length); + if (result != ZIP_OK) + { + throw IOException("Unable to write file data to zip archive"); + } + result = zipCloseFileInZip(archive); + if (result != ZIP_OK) + { + throw IOException("Unable to close file in zip archive"); + } + result = zipClose(archive, 0 /* global comment */); + if (result != ZIP_OK) + { + throw IOException("Unable to close zip archive"); + } +} + void FileUtils::extractFromZip(const char* zipFilePath, const char* src, const char* dest) throw (IOException) { unzFile zipFile = unzOpen(zipFilePath); @@ -504,6 +536,17 @@ void FileUtils::writeFile(const char* path, const char* data, int length) throw stream.write(data,length); } +std::string FileUtils::readFile(const char* path) +{ + std::ifstream inputFile(path, std::ios::in | std::ios::binary); + std::string content; + inputFile.seekg(0, std::ios::end); + content.resize(static_cast(inputFile.tellg())); + inputFile.seekg(0, std::ios::beg); + inputFile.read(&content[0], content.size()); + return content; +} + void FileUtils::copyFile(const char* src, const char* dest) throw (IOException) { #ifdef PLATFORM_UNIX diff --git a/src/FileUtils.h b/src/FileUtils.h index d4ff116..24a241b 100644 --- a/src/FileUtils.h +++ b/src/FileUtils.h @@ -109,6 +109,9 @@ class FileUtils /** Returns the path to a directory for storing temporary files. */ static std::string tempPath(); + /** Add a file to a zip archive, creating it if it does not already exist. */ + static void addToZip(const char* archivePath, const char* path, const char* content, int length) throw (IOException); + /** Extract the file @p src from the zip archive @p zipFile and * write it to @p dest. */ @@ -135,6 +138,8 @@ class FileUtils static void writeFile(const char* path, const char* data, int length) throw (IOException); + static std::string readFile(const char* path) throw (IOException); + /** Changes the current working directory to @p path */ static void chdir(const char* path) throw (IOException); diff --git a/src/StringUtils.h b/src/StringUtils.h index 91f486a..745b71c 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -36,7 +36,7 @@ inline const char* notNullString(const char* text) inline bool endsWith(const std::string& str, const char* text) { size_t length = strlen(text); - return str.find(text,str.size() - length) != 0; + return str.find(text,str.size() - length) != std::string::npos; } inline bool startsWith(const std::string& str, const char* text) diff --git a/src/UpdateDialogWin32.cpp b/src/UpdateDialogWin32.cpp index 3209289..bdc2543 100644 --- a/src/UpdateDialogWin32.cpp +++ b/src/UpdateDialogWin32.cpp @@ -146,7 +146,7 @@ void UpdateDialogWin32::updateFinished() void UpdateDialogWin32::quit() { - PostQuitMessage(0); + PostThreadMessage(GetWindowThreadProcessId(m_window.GetHwnd(), 0 /* process ID */), WM_QUIT, 0, 0); } LRESULT WINAPI UpdateDialogWin32::windowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) diff --git a/src/tests/test-update.rb b/src/tests/test-update.rb index 14293f8..c79a84a 100755 --- a/src/tests/test-update.rb +++ b/src/tests/test-update.rb @@ -18,13 +18,13 @@ if IS_WINDOWS NEWAPP_NAME = "newapp.exe" APP_NAME = "app.exe" UPDATER_NAME = "updater.exe" - ZIP_TOOL = "C:/Cygwin/bin/zip.exe" + ZIP_TOOL = File.expand_path("../zip-tool.exe") else OLDAPP_NAME = "oldapp" NEWAPP_NAME = "newapp" APP_NAME = "app" UPDATER_NAME = "updater" - ZIP_TOOL = "zip" + ZIP_TOOL = File.expand_path("../zip-tool") end file_list_vars = { @@ -42,13 +42,6 @@ def replace_vars(src_file,dest_file,vars) end end -def zip_supports_bzip2(zip_tool) - # Try making an empty zip file with bzip2 compression, if bzip2 is not - # supported, the tool will output an error, otherwise it will output - # "Nothing to do" - return `#{zip_tool} -Z bzip2 testing-bzip2-support.zip`.strip.include?("Nothing to do") -end - # Returns true if |src_file| and |dest_file| have the same contents, type # and permissions or false otherwise def compare_files(src_file, dest_file) @@ -124,19 +117,6 @@ OptionParser.new do |parser| end end.parse! -BZIP2_AVAILABLE = zip_supports_bzip2(ZIP_TOOL) -if (BZIP2_AVAILABLE) - ZIP_FLAGS = "-Z bzip2" -else - ZIP_FLAGS = "" -end - -if (BZIP2_AVAILABLE) - puts "Using bzip2 compression" -else - puts "Using plain old deflate compression - the 'zip' tool does not support bzip2" -end - # Remove the install and package dirs if they # already exist FileUtils.rm_rf(INSTALL_DIR) @@ -172,7 +152,7 @@ FileUtils::chmod 0755, "#{PACKAGE_SRC_DIR}/#{APP_NAME}" # Create .zip packages from source files Dir.mkdir(PACKAGE_DIR) Dir.chdir(PACKAGE_SRC_DIR) do - if !system("#{ZIP_TOOL} #{ZIP_FLAGS} -r #{PACKAGE_DIR}/app-pkg.zip .") + if !system("#{ZIP_TOOL} #{PACKAGE_DIR}/app-pkg.zip .") raise "Unable to create update package" end end diff --git a/src/zip.cpp b/src/zip.cpp new file mode 100644 index 0000000..dd7302f --- /dev/null +++ b/src/zip.cpp @@ -0,0 +1,68 @@ +#include "DirIterator.h" +#include "Log.h" +#include "FileUtils.h" +#include "StringUtils.h" + +#include +#include + +// Simple utility for creating zip files from the +// contents of a directory +// +// The advantage of this over the 'zip' tool on Linux/Mac is consistent +// behavior across platforms and support for Windows. +// +// Usage: zip-tool + +// scan a directory and record paths to files that are found +void scanDir(std::vector& filesFound, const std::string& path) +{ + DirIterator iter(path.c_str()); + while (iter.next()) + { + if (iter.isDir()) + { + if (iter.fileName() == "." || iter.fileName() == "..") + { + continue; + } + scanDir(filesFound, iter.filePath()); + } + else + { + filesFound.push_back(iter.filePath()); + } + } +} + +int main(int argc, char** argv) +{ + if (argc < 3) + { + return 1; + } + + std::string archivePath(argv[1]); + std::string inputDir(argv[2]); + + try + { + std::vector paths; + scanDir(paths, inputDir); + for (std::vector::const_iterator iter = paths.begin(); + iter != paths.end(); + ++iter) + { + std::string path = iter->substr(inputDir.size()+1); + std::string content = FileUtils::readFile(iter->c_str()); + LOG(Info, "Adding " + path + " to archive " + archivePath); + FileUtils::addToZip(archivePath.c_str(), path.c_str(), content.data(), content.length()); + } + } + catch (const std::exception& ex) + { + std::cerr << "Creating zip file failed: " << ex.what() << std::endl; + } + + return 0; +}