Renew the updater branch
Now with some actual consensus on what the updater will do!
This commit is contained in:
51
mmc_updater/src/tests/CMakeLists.txt
Normal file
51
mmc_updater/src/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
|
||||
if (APPLE)
|
||||
set(HELPER_SHARED_SOURCES ../StlSymbolsLeopard.cpp)
|
||||
endif()
|
||||
|
||||
# Create helper binaries for unit tests
|
||||
add_executable(oldapp
|
||||
old_app.cpp
|
||||
${HELPER_SHARED_SOURCES}
|
||||
)
|
||||
add_executable(newapp
|
||||
new_app.cpp
|
||||
${HELPER_SHARED_SOURCES}
|
||||
)
|
||||
|
||||
# Install data files required by unit tests
|
||||
set(TEST_FILES
|
||||
file_list.xml
|
||||
v2_file_list.xml
|
||||
test-update.rb
|
||||
)
|
||||
|
||||
foreach(TEST_FILE ${TEST_FILES})
|
||||
execute_process(
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${TEST_FILE}" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Add unit test binaries
|
||||
macro(ADD_UPDATER_TEST CLASS)
|
||||
set(TEST_TARGET updater_${CLASS})
|
||||
add_executable(${TEST_TARGET} ${CLASS}.cpp)
|
||||
target_link_libraries(${TEST_TARGET} updatershared)
|
||||
add_test(${TEST_TARGET} ${TEST_TARGET})
|
||||
if (APPLE)
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES LINK_FLAGS "-framework Security -framework Cocoa")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
add_updater_test(TestUpdateScript)
|
||||
add_updater_test(TestUpdaterOptions)
|
||||
add_updater_test(TestFileUtils)
|
||||
|
||||
# Add updater that that performs a complete update install
|
||||
# and checks the result
|
||||
find_program(RUBY_BIN ruby)
|
||||
add_test(updater_TestUpdateInstall ${RUBY_BIN} test-update.rb)
|
||||
|
||||
50
mmc_updater/src/tests/TestFileUtils.cpp
Normal file
50
mmc_updater/src/tests/TestFileUtils.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "TestFileUtils.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
void TestFileUtils::testDirName()
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
std::string dirName = FileUtils::dirname("E:/Some Dir/App.exe");
|
||||
TEST_COMPARE(dirName,"E:/Some Dir/");
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestFileUtils::testIsRelative()
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
TEST_COMPARE(FileUtils::isRelative("temp"),true);
|
||||
TEST_COMPARE(FileUtils::isRelative("D:/temp"),false);
|
||||
TEST_COMPARE(FileUtils::isRelative("d:/temp"),false);
|
||||
#else
|
||||
TEST_COMPARE(FileUtils::isRelative("/tmp"),false);
|
||||
TEST_COMPARE(FileUtils::isRelative("tmp"),true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestFileUtils::testSymlinkFileExists()
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
const char* linkName = "link-name";
|
||||
FileUtils::removeFile(linkName);
|
||||
FileUtils::createSymLink(linkName, "target-that-does-not-exist");
|
||||
TEST_COMPARE(FileUtils::fileExists(linkName), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestFileUtils::testStandardDirs()
|
||||
{
|
||||
std::string tmpDir = FileUtils::tempPath();
|
||||
TEST_COMPARE(FileUtils::fileExists(tmpDir.data()), true);
|
||||
}
|
||||
|
||||
int main(int,char**)
|
||||
{
|
||||
TestList<TestFileUtils> tests;
|
||||
tests.addTest(&TestFileUtils::testDirName);
|
||||
tests.addTest(&TestFileUtils::testIsRelative);
|
||||
tests.addTest(&TestFileUtils::testSymlinkFileExists);
|
||||
tests.addTest(&TestFileUtils::testStandardDirs);
|
||||
return TestUtils::runTest(tests);
|
||||
}
|
||||
10
mmc_updater/src/tests/TestFileUtils.h
Normal file
10
mmc_updater/src/tests/TestFileUtils.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class TestFileUtils
|
||||
{
|
||||
public:
|
||||
void testDirName();
|
||||
void testIsRelative();
|
||||
void testSymlinkFileExists();
|
||||
void testStandardDirs();
|
||||
};
|
||||
48
mmc_updater/src/tests/TestUpdateScript.cpp
Normal file
48
mmc_updater/src/tests/TestUpdateScript.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "TestUpdateScript.h"
|
||||
|
||||
#include "TestUtils.h"
|
||||
#include "UpdateScript.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
void TestUpdateScript::testV2Script()
|
||||
{
|
||||
UpdateScript newFormat;
|
||||
UpdateScript oldFormat;
|
||||
|
||||
newFormat.parse("file_list.xml");
|
||||
oldFormat.parse("v2_file_list.xml");
|
||||
|
||||
TEST_COMPARE(newFormat.filesToInstall(),oldFormat.filesToInstall());
|
||||
TEST_COMPARE(newFormat.filesToUninstall(),oldFormat.filesToUninstall());
|
||||
}
|
||||
|
||||
void TestUpdateScript::testPermissions()
|
||||
{
|
||||
UpdateScript script;
|
||||
script.parse("file_list.xml");
|
||||
|
||||
for (std::vector<UpdateScriptFile>::const_iterator iter = script.filesToInstall().begin();
|
||||
iter != script.filesToInstall().end();
|
||||
iter++)
|
||||
{
|
||||
if (iter->isMainBinary)
|
||||
{
|
||||
TEST_COMPARE(iter->permissions,0755);
|
||||
}
|
||||
if (!iter->linkTarget.empty())
|
||||
{
|
||||
TEST_COMPARE(iter->permissions,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int,char**)
|
||||
{
|
||||
TestList<TestUpdateScript> tests;
|
||||
tests.addTest(&TestUpdateScript::testV2Script);
|
||||
tests.addTest(&TestUpdateScript::testPermissions);
|
||||
return TestUtils::runTest(tests);
|
||||
}
|
||||
|
||||
9
mmc_updater/src/tests/TestUpdateScript.h
Normal file
9
mmc_updater/src/tests/TestUpdateScript.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
class TestUpdateScript
|
||||
{
|
||||
public:
|
||||
void testV2Script();
|
||||
void testPermissions();
|
||||
};
|
||||
|
||||
68
mmc_updater/src/tests/TestUpdaterOptions.cpp
Normal file
68
mmc_updater/src/tests/TestUpdaterOptions.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "TestUpdaterOptions.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "Platform.h"
|
||||
#include "TestUtils.h"
|
||||
#include "UpdaterOptions.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void TestUpdaterOptions::testOldFormatArgs()
|
||||
{
|
||||
const int argc = 6;
|
||||
char* argv[argc];
|
||||
argv[0] = strdup("updater");
|
||||
|
||||
std::string currentDir("CurrentDir=");
|
||||
const char* appDir = 0;
|
||||
|
||||
// CurrentDir is the path to the directory containing the main
|
||||
// Mendeley Desktop binary, on Linux and Mac this differs from
|
||||
// the root of the install directory
|
||||
#ifdef PLATFORM_LINUX
|
||||
appDir = "/tmp/path-to-app/lib/mendeleydesktop/libexec/";
|
||||
FileUtils::mkpath(appDir);
|
||||
#elif defined(PLATFORM_MAC)
|
||||
appDir = "/tmp/path-to-app/Contents/MacOS/";
|
||||
FileUtils::mkpath(appDir);
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
appDir = "C:/path/to/app/";
|
||||
#endif
|
||||
currentDir += appDir;
|
||||
|
||||
argv[1] = strdup(currentDir.c_str());
|
||||
argv[2] = strdup("TempDir=/tmp/updater");
|
||||
argv[3] = strdup("UpdateScriptFileName=/tmp/updater/file_list.xml");
|
||||
argv[4] = strdup("AppFileName=/path/to/app/theapp");
|
||||
argv[5] = strdup("PID=123456");
|
||||
|
||||
UpdaterOptions options;
|
||||
options.parse(argc,argv);
|
||||
|
||||
TEST_COMPARE(options.mode,UpdateInstaller::Setup);
|
||||
#ifdef PLATFORM_LINUX
|
||||
TEST_COMPARE(options.installDir,"/tmp/path-to-app");
|
||||
#elif defined(PLATFORM_MAC)
|
||||
// /tmp is a symlink to /private/tmp on Mac
|
||||
TEST_COMPARE(options.installDir,"/private/tmp/path-to-app");
|
||||
#else
|
||||
TEST_COMPARE(options.installDir,"C:/path/to/app/");
|
||||
#endif
|
||||
TEST_COMPARE(options.packageDir,"/tmp/updater");
|
||||
TEST_COMPARE(options.scriptPath,"/tmp/updater/file_list.xml");
|
||||
TEST_COMPARE(options.waitPid,123456);
|
||||
|
||||
for (int i=0; i < argc; i++)
|
||||
{
|
||||
free(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int,char**)
|
||||
{
|
||||
TestList<TestUpdaterOptions> tests;
|
||||
tests.addTest(&TestUpdaterOptions::testOldFormatArgs);
|
||||
return TestUtils::runTest(tests);
|
||||
}
|
||||
|
||||
8
mmc_updater/src/tests/TestUpdaterOptions.h
Normal file
8
mmc_updater/src/tests/TestUpdaterOptions.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
class TestUpdaterOptions
|
||||
{
|
||||
public:
|
||||
void testOldFormatArgs();
|
||||
};
|
||||
|
||||
108
mmc_updater/src/tests/TestUtils.h
Normal file
108
mmc_updater/src/tests/TestUtils.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class T>
|
||||
class TestList
|
||||
{
|
||||
public:
|
||||
void addTest(void (T::*test)())
|
||||
{
|
||||
m_tests.push_back(std::mem_fun(test));
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return m_tests.size();
|
||||
}
|
||||
|
||||
void runTest(T* testInstance, int i)
|
||||
{
|
||||
m_tests.at(i)(testInstance);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::mem_fun_t<void,T> > m_tests;
|
||||
};
|
||||
|
||||
class TestUtils
|
||||
{
|
||||
public:
|
||||
template <class X, class Y>
|
||||
static void compare(const X& x, const Y& y, const char* xString, const char* yString)
|
||||
{
|
||||
if (x != y)
|
||||
{
|
||||
throw "Actual and expected values differ. "
|
||||
"Actual: " + toString(x,xString) +
|
||||
" Expected: " + toString(y,yString);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::string toString(T value, const char* context)
|
||||
{
|
||||
return "Unprintable: " + std::string(context);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static int runTest(class TestList<T>& tests) throw ()
|
||||
{
|
||||
std::string errorText;
|
||||
try
|
||||
{
|
||||
T testInstance;
|
||||
for (int i=0; i < tests.size(); i++)
|
||||
{
|
||||
tests.runTest(&testInstance,i);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
errorText = ex.what();
|
||||
}
|
||||
catch (const std::string& error)
|
||||
{
|
||||
errorText = error;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
errorText = "Unknown exception";
|
||||
}
|
||||
|
||||
if (errorText.empty())
|
||||
{
|
||||
std::cout << "Test passed" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Test failed: " << errorText << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline std::string TestUtils::toString(const std::string& value, const char*)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
template <>
|
||||
inline std::string TestUtils::toString(std::string value, const char*)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
template <>
|
||||
inline std::string TestUtils::toString(const char* value, const char*)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
#define TEST_COMPARE(x,y) \
|
||||
TestUtils::compare(x,y,#x,#y);
|
||||
|
||||
|
||||
52
mmc_updater/src/tests/file_list.xml
Normal file
52
mmc_updater/src/tests/file_list.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0"?>
|
||||
<update version="3">
|
||||
<targetVersion>2.0</targetVersion>
|
||||
<platform>Test</platform>
|
||||
<dependencies>
|
||||
<!-- The new updater is standalone and has no dependencies,
|
||||
except for standard system libraries.
|
||||
!-->
|
||||
</dependencies>
|
||||
<packages>
|
||||
<package>
|
||||
<name>app-pkg</name>
|
||||
<hash>$APP_PACKAGE_HASH</hash>
|
||||
<size>$APP_PACKAGE_SIZE</size>
|
||||
<source>http://some/dummy/URL</source>
|
||||
</package>
|
||||
</packages>
|
||||
<install>
|
||||
<file>
|
||||
<name>$APP_FILENAME</name>
|
||||
<hash>$UPDATED_APP_HASH</hash>
|
||||
<size>$UPDATED_APP_SIZE</size>
|
||||
<permissions>0755</permissions>
|
||||
<package>app-pkg</package>
|
||||
<is-main-binary>true</is-main-binary>
|
||||
</file>
|
||||
<file>
|
||||
<name>$UPDATER_FILENAME</name>
|
||||
<hash>$UPDATER_HASH</hash>
|
||||
<size>$UPDATER_SIZE</size>
|
||||
<permissions>0755</permissions>
|
||||
</file>
|
||||
<!-- Test symlink !-->
|
||||
<file>
|
||||
<name>test-dir/app-symlink</name>
|
||||
<target>../app</target>
|
||||
</file>
|
||||
<!-- Test file in new directory !-->
|
||||
<file>
|
||||
<name>new-dir/new-dir2/new-file.txt</name>
|
||||
<hash>$TEST_FILENAME</hash>
|
||||
<size>$TEST_SIZE</size>
|
||||
<package>app-pkg</package>
|
||||
<permissions>0644</permissions>
|
||||
</file>
|
||||
</install>
|
||||
<uninstall>
|
||||
<!-- TODO - List some files to uninstall here !-->
|
||||
<file>file-to-uninstall.txt</file>
|
||||
<file>symlink-to-file-to-uninstall.txt</file>
|
||||
</uninstall>
|
||||
</update>
|
||||
8
mmc_updater/src/tests/new_app.cpp
Normal file
8
mmc_updater/src/tests/new_app.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int,char**)
|
||||
{
|
||||
std::cout << "new app starting" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
7
mmc_updater/src/tests/old_app.cpp
Normal file
7
mmc_updater/src/tests/old_app.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int,char**)
|
||||
{
|
||||
std::cout << "old app starting" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
218
mmc_updater/src/tests/test-update.rb
Executable file
218
mmc_updater/src/tests/test-update.rb
Executable file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
require 'fileutils.rb'
|
||||
require 'find'
|
||||
require 'rbconfig'
|
||||
require 'optparse'
|
||||
|
||||
# Install directory - this contains a space to check
|
||||
# for correct escaping of paths when passing comamnd
|
||||
# line arguments under Windows
|
||||
INSTALL_DIR = File.expand_path("install dir/")
|
||||
PACKAGE_DIR = File.expand_path("package-dir/")
|
||||
PACKAGE_SRC_DIR = File.expand_path("package-src-dir/")
|
||||
IS_WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
||||
|
||||
if IS_WINDOWS
|
||||
OLDAPP_NAME = "oldapp.exe"
|
||||
NEWAPP_NAME = "newapp.exe"
|
||||
APP_NAME = "app.exe"
|
||||
UPDATER_NAME = "updater.exe"
|
||||
ZIP_TOOL = File.expand_path("../zip-tool.exe")
|
||||
else
|
||||
OLDAPP_NAME = "oldapp"
|
||||
NEWAPP_NAME = "newapp"
|
||||
APP_NAME = "app"
|
||||
UPDATER_NAME = "updater"
|
||||
ZIP_TOOL = File.expand_path("../zip-tool")
|
||||
end
|
||||
|
||||
file_list_vars = {
|
||||
"APP_FILENAME" => APP_NAME,
|
||||
"UPDATER_FILENAME" => UPDATER_NAME
|
||||
}
|
||||
|
||||
def replace_vars(src_file,dest_file,vars)
|
||||
content = File.read(src_file)
|
||||
vars.each do |key,value|
|
||||
content.gsub! "$#{key}",value
|
||||
end
|
||||
File.open(dest_file,'w') do |file|
|
||||
file.print content
|
||||
end
|
||||
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)
|
||||
if File.ftype(src_file) != File.ftype(dest_file)
|
||||
$stderr.puts "Type of file #{src_file} and #{dest_file} differ"
|
||||
return false
|
||||
end
|
||||
|
||||
if File.file?(src_file) && !FileUtils.identical?(src_file, dest_file)
|
||||
$stderr.puts "Contents of file #{src_file} and #{dest_file} differ"
|
||||
return false
|
||||
end
|
||||
|
||||
src_stat = File.stat(src_file)
|
||||
dest_stat = File.stat(dest_file)
|
||||
|
||||
if src_stat.mode != dest_stat.mode
|
||||
$stderr.puts "Permissions of #{src_file} and #{dest_file} differ"
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
# Compares the contents of two directories and returns a map of (file path => change type)
|
||||
# for files and directories which differ between the two
|
||||
def compare_dirs(src_dir, dest_dir)
|
||||
src_dir += '/' if !src_dir.end_with?('/')
|
||||
dest_dir += '/' if !dest_dir.end_with?('/')
|
||||
|
||||
src_file_map = {}
|
||||
Find.find(src_dir) do |src_file|
|
||||
src_file = src_file[src_dir.length..-1]
|
||||
src_file_map[src_file] = nil
|
||||
end
|
||||
|
||||
change_map = {}
|
||||
Find.find(dest_dir) do |dest_file|
|
||||
dest_file = dest_file[dest_dir.length..-1]
|
||||
|
||||
if !src_file_map.include?(dest_file)
|
||||
change_map[dest_file] = :deleted
|
||||
elsif !compare_files("#{src_dir}/#{dest_file}", "#{dest_dir}/#{dest_file}")
|
||||
change_map[dest_file] = :updated
|
||||
end
|
||||
|
||||
src_file_map.delete(dest_file)
|
||||
end
|
||||
|
||||
src_file_map.each do |file|
|
||||
change_map[file] = :added
|
||||
end
|
||||
|
||||
return change_map
|
||||
end
|
||||
|
||||
def create_test_file(name, content)
|
||||
File.open(name, 'w') do |file|
|
||||
file.puts content
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
force_elevation = false
|
||||
run_in_debugger = false
|
||||
|
||||
OptionParser.new do |parser|
|
||||
parser.on("-f","--force-elevated","Force the updater to elevate itself") do
|
||||
force_elevation = true
|
||||
end
|
||||
parser.on("-d","--debug","Run the updater under GDB") do
|
||||
run_in_debugger = true
|
||||
end
|
||||
end.parse!
|
||||
|
||||
# copy 'src' to 'dest', preserving the attributes
|
||||
# of 'src'
|
||||
def copy_file(src, dest)
|
||||
FileUtils.cp src, dest, :preserve => true
|
||||
end
|
||||
|
||||
# Remove the install and package dirs if they
|
||||
# already exist
|
||||
FileUtils.rm_rf(INSTALL_DIR)
|
||||
FileUtils.rm_rf(PACKAGE_DIR)
|
||||
FileUtils.rm_rf(PACKAGE_SRC_DIR)
|
||||
|
||||
# Create the install directory with the old app
|
||||
Dir.mkdir(INSTALL_DIR)
|
||||
copy_file OLDAPP_NAME, "#{INSTALL_DIR}/#{APP_NAME}"
|
||||
|
||||
# Create a dummy file to uninstall
|
||||
uninstall_test_file = create_test_file("#{INSTALL_DIR}/file-to-uninstall.txt", "this file should be removed after the update")
|
||||
uninstall_test_symlink = if not IS_WINDOWS
|
||||
FileUtils.ln_s("#{INSTALL_DIR}/file-to-uninstall.txt", "#{INSTALL_DIR}/symlink-to-file-to-uninstall.txt")
|
||||
else
|
||||
create_test_file("#{INSTALL_DIR}/symlink-to-file-to-uninstall.txt", "dummy file. this is a symlink on Unix")
|
||||
end
|
||||
|
||||
# Populate package source dir with files to install
|
||||
Dir.mkdir(PACKAGE_SRC_DIR)
|
||||
nested_dir_path = "#{PACKAGE_SRC_DIR}/new-dir/new-dir2"
|
||||
FileUtils.mkdir_p(nested_dir_path)
|
||||
FileUtils::chmod 0755, "#{PACKAGE_SRC_DIR}/new-dir"
|
||||
FileUtils::chmod 0755, "#{PACKAGE_SRC_DIR}/new-dir/new-dir2"
|
||||
nested_dir_test_file = "#{nested_dir_path}/new-file.txt"
|
||||
File.open(nested_dir_test_file,'w') do |file|
|
||||
file.puts "this is a new file in a new nested dir"
|
||||
end
|
||||
FileUtils::chmod 0644, nested_dir_test_file
|
||||
copy_file NEWAPP_NAME, "#{PACKAGE_SRC_DIR}/#{APP_NAME}"
|
||||
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} #{PACKAGE_DIR}/app-pkg.zip .")
|
||||
raise "Unable to create update package"
|
||||
end
|
||||
end
|
||||
|
||||
# Copy the install script and updater to the target
|
||||
# directory
|
||||
replace_vars("file_list.xml","#{PACKAGE_DIR}/file_list.xml",file_list_vars)
|
||||
copy_file "../#{UPDATER_NAME}", "#{PACKAGE_DIR}/#{UPDATER_NAME}"
|
||||
|
||||
# Run the updater using the new syntax
|
||||
#
|
||||
# Run the application from the install directory to
|
||||
# make sure that it looks in the correct directory for
|
||||
# the file_list.xml file and packages
|
||||
#
|
||||
install_path = File.expand_path(INSTALL_DIR)
|
||||
Dir.chdir(INSTALL_DIR) do
|
||||
flags = "--force-elevated" if force_elevation
|
||||
debug_flags = "gdb --args" if run_in_debugger
|
||||
cmd = "#{debug_flags} #{PACKAGE_DIR}/#{UPDATER_NAME} #{flags} --install-dir \"#{install_path}\" --package-dir \"#{PACKAGE_DIR}\" --script file_list.xml --auto-close"
|
||||
puts "Running '#{cmd}'"
|
||||
system(cmd)
|
||||
end
|
||||
|
||||
# TODO - Correctly wait until updater has finished
|
||||
sleep(1)
|
||||
|
||||
# Check that the app was updated
|
||||
app_path = "#{INSTALL_DIR}/#{APP_NAME}"
|
||||
output = `"#{app_path}"`
|
||||
if (output.strip != "new app starting")
|
||||
throw "Updated app produced unexpected output: #{output}"
|
||||
end
|
||||
|
||||
# Check that the packaged dir and install dir match
|
||||
dir_diff = compare_dirs(PACKAGE_SRC_DIR, INSTALL_DIR)
|
||||
ignored_files = ["test-dir", "test-dir/app-symlink", UPDATER_NAME]
|
||||
have_unexpected_change = false
|
||||
dir_diff.each do |path, change_type|
|
||||
if !ignored_files.include?(path)
|
||||
case change_type
|
||||
when :added
|
||||
$stderr.puts "File #{path} was not installed"
|
||||
when :changed
|
||||
$stderr.puts "File #{path} differs between install and package dir"
|
||||
when :deleted
|
||||
$stderr.puts "File #{path} was not uninstalled"
|
||||
end
|
||||
have_unexpected_change = true
|
||||
end
|
||||
end
|
||||
|
||||
if have_unexpected_change
|
||||
throw "Unexpected differences between packaging and update dir"
|
||||
end
|
||||
|
||||
puts "Test passed"
|
||||
67
mmc_updater/src/tests/v2_file_list.xml
Normal file
67
mmc_updater/src/tests/v2_file_list.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- The v2-compatible attribute lets the update script parser
|
||||
know that it is dealing with a script structured for backwards
|
||||
compatibility with the MD <= 1.0 updater.
|
||||
!-->
|
||||
<update version="3" v2-compatible="true">
|
||||
<targetVersion>2.0</targetVersion>
|
||||
<platform>Test</platform>
|
||||
<dependencies>
|
||||
<!-- The new updater is standalone and has no dependencies,
|
||||
except for standard system libraries and itself.
|
||||
!-->
|
||||
</dependencies>
|
||||
<packages>
|
||||
<package>
|
||||
<name>app-pkg</name>
|
||||
<hash>$APP_PACKAGE_HASH</hash>
|
||||
<size>$APP_PACKAGE_SIZE</size>
|
||||
<source>http://some/dummy/URL</source>
|
||||
</package>
|
||||
</packages>
|
||||
|
||||
<!-- For compatibility with the update download in MD <= 1.0,
|
||||
an <install> section lists the packages to download and
|
||||
the real list of files to install is in the <install-v3>
|
||||
section. !-->
|
||||
<install>
|
||||
<!-- A duplicate of the <packages> section should appear here,
|
||||
except that each package is listed using the same structure
|
||||
as files in the install-v3/files section.
|
||||
!-->
|
||||
</install>
|
||||
<install-v3>
|
||||
<file>
|
||||
<name>$APP_FILENAME</name>
|
||||
<hash>$UPDATED_APP_HASH</hash>
|
||||
<size>$UPDATED_APP_SIZE</size>
|
||||
<permissions>0755</permissions>
|
||||
<package>app-pkg</package>
|
||||
<is-main-binary>true</is-main-binary>
|
||||
</file>
|
||||
<file>
|
||||
<name>$UPDATER_FILENAME</name>
|
||||
<hash>$UPDATER_HASH</hash>
|
||||
<size>$UPDATER_SIZE</size>
|
||||
<permissions>0755</permissions>
|
||||
</file>
|
||||
<!-- Test symlink !-->
|
||||
<file>
|
||||
<name>test-dir/app-symlink</name>
|
||||
<target>../app</target>
|
||||
</file>
|
||||
<file>
|
||||
<name>new-dir/new-dir2/new-file.txt</name>
|
||||
<hash>$TEST_FILENAME</hash>
|
||||
<size>$TEST_SIZE</size>
|
||||
<package>app-pkg</package>
|
||||
<permissions>0644</permissions>
|
||||
</file>
|
||||
</install-v3>
|
||||
<uninstall>
|
||||
<!-- TODO - List some files to uninstall here !-->
|
||||
<file>file-to-uninstall.txt</file>
|
||||
<file>symlink-to-file-to-uninstall.txt</file>
|
||||
</uninstall>
|
||||
</update>
|
||||
Reference in New Issue
Block a user