]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'Applications/19.04'
authorNate Graham <nate@kde.org>
Sun, 24 Mar 2019 17:31:44 +0000 (11:31 -0600)
committerNate Graham <nate@kde.org>
Sun, 24 Mar 2019 17:31:44 +0000 (11:31 -0600)
CMakeLists.txt
cmake/FindGem.cmake [new file with mode: 0644]
cmake/FindGem.cmake.in [new file with mode: 0644]
src/panels/information/informationpanel.cpp
src/settings/services/servicemenudeinstallation
src/settings/services/servicemenuinstallation
src/settings/services/test/service_menu_deinstallation_test.rb [new file with mode: 0644]
src/settings/services/test/service_menu_installation_test.rb [new file with mode: 0644]
src/settings/services/test/test_helper.rb [new file with mode: 0644]
src/settings/services/test/test_run.rb [new file with mode: 0755]
src/tests/CMakeLists.txt

index 924ce51107c3c04f3a2d5db64543a9e93d5d65ee..474fbc839199b401e1219e4fa707b9062e020d30 100644 (file)
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0)
 
 # KDE Application Version, managed by release script
 set (KDE_APPLICATIONS_VERSION_MAJOR "19")
-set (KDE_APPLICATIONS_VERSION_MINOR "03")
-set (KDE_APPLICATIONS_VERSION_MICRO "80")
+set (KDE_APPLICATIONS_VERSION_MINOR "07")
+set (KDE_APPLICATIONS_VERSION_MICRO "70")
 set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}")
 project(Dolphin VERSION ${KDE_APPLICATIONS_VERSION})
 
diff --git a/cmake/FindGem.cmake b/cmake/FindGem.cmake
new file mode 100644 (file)
index 0000000..11c9c67
--- /dev/null
@@ -0,0 +1,39 @@
+#=============================================================================
+# Copyright (c) 2019 Harald Sitter <sitter@kde.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+# In this scope it's the dir we are in, in the function scope it will be the
+# caller's dir. So, keep our dir in a var.
+set(FINDGEM_MODULES_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+function(find_gem GEM_NAME)
+    set(GEM_PACKAGE "Gem:${GEM_NAME}")
+
+    configure_file(${FINDGEM_MODULES_DIR}/FindGem.cmake.in Find${GEM_PACKAGE}.cmake @ONLY)
+
+    set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}" ${CMAKE_MODULE_PATH})
+    find_package(${GEM_PACKAGE} ${ARGN})
+endfunction()
diff --git a/cmake/FindGem.cmake.in b/cmake/FindGem.cmake.in
new file mode 100644 (file)
index 0000000..0dcc677
--- /dev/null
@@ -0,0 +1,53 @@
+#=============================================================================
+# Copyright (c) 2019 Harald Sitter <sitter@kde.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+find_program(RUBY_EXE ruby)
+if(NOT RUBY_EXE)
+    message(WARNING "Could not find ruby program")
+    return()
+endif()
+
+execute_process(
+    COMMAND ${RUBY_EXE} -e "require '@GEM_NAME@'"
+    ERROR_VARIABLE ERROR_VAR
+    RESULT_VARIABLE RESULT_VAR
+)
+
+if(RESULT_VAR EQUAL 0)
+    set(@GEM_PACKAGE@_FOUND TRUE)
+else()
+    message(WARNING ${ERROR_VAR})
+    return()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(@GEM_PACKAGE@
+    FOUND_VAR
+        @GEM_PACKAGE@_FOUND
+    REQUIRED_VARS
+        @GEM_PACKAGE@_FOUND
+)
index cd8b6b38d354629a2f60b3db9747720c16427087..e5257bc72556839db0e55fa3570a98ffaaf92302 100644 (file)
@@ -185,7 +185,8 @@ void InformationPanel::showContextMenu(const QPoint &pos) {
     dateformatAction->setChecked(InformationPanelSettings::dateFormat() == static_cast<int>(Baloo::DateFormats::ShortFormat));
 
     popup.addSeparator();
-    foreach (QAction* action, customContextMenuActions()) {
+    const auto actions = customContextMenuActions();
+    for (QAction *action : actions) {
         popup.addAction(action);
     }
 
@@ -311,7 +312,7 @@ void InformationPanel::slotFilesAdded(const QString& directory)
 
 void InformationPanel::slotFilesChanged(const QStringList& files)
 {
-    foreach (const QString& fileName, files) {
+    for (const QString& fileName : files) {
         if (m_shownUrl == QUrl::fromLocalFile(fileName)) {
             showItemInfo();
             break;
@@ -321,7 +322,7 @@ void InformationPanel::slotFilesChanged(const QStringList& files)
 
 void InformationPanel::slotFilesRemoved(const QStringList& files)
 {
-    foreach (const QString& fileName, files) {
+    for (const QString& fileName : files) {
         if (m_shownUrl == QUrl::fromLocalFile(fileName)) {
             // the currently shown item has been removed, show
             // the parent directory as fallback
index 5e4234262cc2e88346c33e09f77ac030e383a296..9e090e2cda57716bc906c2cef2e5b03e25149c00 100755 (executable)
@@ -1,37 +1,72 @@
 #!/usr/bin/env ruby
+
+# Copyright (C) 2009 Jonathan Schmidt-DominĂ© <devel@the-user.org>
+# Copyright (C) 2019 Harald Sitter <sitter@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
 require 'fileutils'
-archive = ARGV[0]
-if archive[(archive.length - 8)..(archive.length)] == ".desktop"
-    FileUtils.rm(`qtpaths --writable-path GenericDataLocation`.strip!  + "/kservices5/ServiceMenus/" + File.basename(archive))
-    exit(0)
+
+ARCHIVE = ARGV[0]
+
+# @param log_msg [String] error that gets logged to CLI
+def fail(log_msg: nil)
+  # FIXME: this is not translated...
+  msg = 'Dolphin service menu installation failed'
+  warn log_msg if log_msg
+  system('kdialog', '--passivepopup', msg, '15')
+  abort
 end
-dir = archive + "-dir"
-# try: deinstall.sh
-# try: deinstall
-# try: installKDE4.sh
-# try: installKDE4
-# try: install.sh
-# try: install
-while true
-    dd = Dir.new(dir)
-    break if dd.count != 3
-    odir = dir
-    for entry in dd
-        dir += "/" + entry if entry != "." && entry != ".."
-    end
-    if !File.directory? dir
-        dir = odir
-        break
-    end
+
+if ARCHIVE.end_with?('.desktop')
+  data_location = `qtpaths --writable-path GenericDataLocation`.strip
+  unless $?.success?
+    fail(log_msg: "Could not get GenericDataLocation #{data_location}")
+  end
+  FileUtils.rm("#{data_location}/kservices5/ServiceMenus/#{File.basename(ARCHIVE)}")
+  exit(0)
 end
-Dir.chdir(dir)
-def fail()
-    system("kdialog --passivepopup \"Deinstallation failed\" 15")
-    exit(-1)
+dir = "#{ARCHIVE}-dir"
+
+deinstaller = nil
+%w[deinstall.sh deinstall].find do |script|
+  deinstaller = Dir.glob("#{dir}/**/#{script}")[0]
 end
-if !((File.exist?(file = "./deinstall.sh") || File.exist?(file = "./deinstall")) && system(file))
-    fail() if !File.exist?(file = "./installKDE4.sh") && !File.exist?(file = "./installKDE4") && !File.exist?(file = "./install.sh") && !File.exist?(file = "./install")
-File.new(file).chmod(0700)
-    fail() if !system(file + " --remove") && !system(file + " --delete") && !system(file + " --uninstall") && !system(file + " --deinstall")
+
+installer = nil
+%w[install-it.sh install-it installKDE4.sh installKDE4 install.sh install].find do |script|
+  installer = Dir.glob("#{dir}/**/#{script}")[0]
+end
+
+Dir.chdir(dir) do
+  deinstalled = false
+
+  [deinstaller, installer].uniq.compact.each { |f| File.chmod(0o700, f) }
+
+  if deinstaller
+    puts "[servicemenudeinstallation]: Trying to run deinstaller #{deinstaller}"
+    deinstalled = system(deinstaller)
+  elsif installer
+    puts "[servicemenudeinstallation]: Trying to run installer #{installer}"
+    %w[--remove --delete --uninstall --deinstall].any? do |arg|
+      deinstalled = system(installer, arg)
+    end
+  end
+
+  fail unless deinstalled
 end
+
 FileUtils.rm_r(dir)
index 60b699bb6041b3cce0cd4a28f48e6a4c5c188d1d..e2d42bfbf4f0f92f48d3085a58db888df2e7133d 100755 (executable)
 #!/usr/bin/env ruby
-require 'pathname'
+
+# Copyright (C) 2009 Jonathan Schmidt-DominĂ© <devel@the-user.org>
+# Copyright (C) 2019 Harald Sitter <sitter@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
 require 'fileutils'
-archive = ARGV[0]
-$servicedir = `qtpaths --writable-path GenericDataLocation`.strip!  + "/kservices5/ServiceMenus/"
-FileUtils.mkdir_p($servicedir) if !File.exist?($servicedir)
-if archive[(archive.length - 8)..(archive.length - 1)] == ".desktop"
-    puts "Single-File Service-Menu"
-    puts archive
-    puts $servicedir
-    FileUtils.cp(archive, $servicedir);
-    exit(0)
+
+ARCHIVE_UNCOMPRESSORS = {
+  'application/x-tar' => :"tar -xf %s -C %s",
+  'application/tar' => :"tar -xf %s -C %s",
+  'application/x-gzip' => :"tar -zxf %s -C %s",
+  'application/gzip' => :"tar -zxf %s -C %s",
+  'application/x-gzip-compressed-tar' => :"tar -zxf %s -C %s",
+  'application/gzip-compressed-tar' => :"tar -zxf %s -C %s",
+  'application/x-gzip-compressed' => :"tar -zxf %s -C %s",
+  'application/gzip-compressed' => :"tar -zxf %s -C %s",
+  'application/bzip' => :"tar -jxf %s -C %s",
+  'application/bzip2' => :"tar -jxf %s -C %s",
+  'application/x-bzip' => :"tar -jxf %s -C %s",
+  'application/x-bzip2' => :"tar -jxf %s -C %s",
+  'application/bzip-compressed' => :"tar -jxf %s -C %s",
+  'application/bzip2-compressed' => :"tar -jxf %s -C %s",
+  'application/x-bzip-compressed' => :"tar -jxf %s -C %s",
+  'application/x-bzip2-compressed' => :"tar -jxf %s -C %s",
+  'application/bzip-compressed-tar' => :"tar -jxf %s -C %s",
+  'application/bzip2-compressed-tar' => :"tar -jxf %s -C %s",
+  'application/x-bzip-compressed-tar' => :"tar -jxf %s -C %s",
+  'application/x-bzip2-compressed-tar' => :"tar -jxf %s -C %s",
+  'application/zip' => :"unzip %s -d %s",
+  'application/x-zip' => :"unzip %s -d %s",
+  'application/x-zip-compressed' => :"unzip %s -d %s",
+  'multipart/x-zip' => :"unzip %s -d %s",
+  'application/tgz' => :"tar -zxf %s -C %s",
+  'application/x-compressed-gtar' => :"tar -zxf %s -C %s",
+  'file/tgz' => :"tar -zxf %s -C %s",
+  'multipart/x-tar-gz' => :"tar -zxf %s -C %s",
+  'application/x-gunzip' => :"tar -zxf %s -C %s",
+  'application/gzipped' => :"tar -zxf %s -C %s",
+  'gzip/document' => :"tar -zxf %s -C %s",
+  'application/x-bz2 ' => :"tar -jxf %s -C %s",
+  'application/x-gtar' => :"tar -xf %s -C %s",
+  'multipart/x-tar' => :"tar -xf %s -C %s"
+}
+
+ARCHIVE = ARGV[0]
+
+# @param log_msg [String] error that gets logged to CLI
+def fail(log_msg: nil)
+  # FIXME: this is not translated...
+  msg = 'Dolphin service menu installation failed'
+  warn log_msg if log_msg
+  system('kdialog', '--passivepopup', msg, '15')
+  abort
 end
-def mimeType(filename)
-    IO.popen("file --mime-type -b " + filename).gets().strip!()
+
+def mime_type(filename)
+  ret = `xdg-mime query filetype #{filename}`.strip
+  return ret if $?.success?
+
+  warn 'Failed to xdg-mime'
+  fail(log_msg: "Failed to xdg-mime #{filename}: #{ret}")
 end
-$archivetypes = { "application/x-tar" => :"tar -xf %s -C %s",
-        "application/tar" => :"tar -xf %s -C %s",
-        "application/x-gzip" => :"tar -zxf %s -C %s",
-        "application/gzip" => :"tar -zxf %s -C %s",
-        "application/x-gzip-compressed-tar" => :"tar -zxf %s -C %s",
-        "application/gzip-compressed-tar" => :"tar -zxf %s -C %s",
-        "application/x-gzip-compressed" => :"tar -zxf %s -C %s",
-        "application/gzip-compressed" => :"tar -zxf %s -C %s",
-        "application/bzip" => :"tar -jxf %s -C %s",
-        "application/bzip2" => :"tar -jxf %s -C %s",
-        "application/x-bzip" => :"tar -jxf %s -C %s",
-        "application/x-bzip2" => :"tar -jxf %s -C %s",
-        "application/bzip-compressed" => :"tar -jxf %s -C %s",
-        "application/bzip2-compressed" => :"tar -jxf %s -C %s",
-        "application/x-bzip-compressed" => :"tar -jxf %s -C %s",
-        "application/x-bzip2-compressed" => :"tar -jxf %s -C %s",
-        "application/bzip-compressed-tar" => :"tar -jxf %s -C %s",
-        "application/bzip2-compressed-tar" => :"tar -jxf %s -C %s",
-        "application/x-bzip-compressed-tar" => :"tar -jxf %s -C %s",
-        "application/x-bzip2-compressed-tar" => :"tar -jxf %s -C %s",
-        "application/zip" => :"unzip %s -d %s",
-        "application/x-zip" => :"unzip %s -d %s",
-        "application/x-zip-compressed" => :"unzip %s -d %s",
-        "multipart/x-zip" => :"unzip %s -d %s",
-        "application/tgz" => :"tar -zxf %s -C %s",
-        "application/x-compressed-gtar" => :"tar -zxf %s -C %s",
-        "file/tgz" => :"tar -zxf %s -C %s",
-        "multipart/x-tar-gz" => :"tar -zxf %s -C %s",
-        "application/x-gunzip" => :"tar -zxf %s -C %s",
-        "application/gzipped" => :"tar -zxf %s -C %s",
-        "gzip/document" => :"tar -zxf %s -C %s",
-        "application/x-bz2 " => :"tar -jxf %s -C %s",
-        "application/x-gtar" => :"tar -xf %s -C %s",
-        "multipart/x-tar" => :"tar -xf %s -C %s"
-}
+
 def uncompress(filename, output)
-    system(sprintf($archivetypes[mimeType(filename)].to_s, filename, output))
+  uncompressor = ARCHIVE_UNCOMPRESSORS.fetch(mime_type(filename)).to_s
+  system(format(uncompressor, filename, output))
+rescue KeyError => e
+  # If a mimetype doesn't have an uncompressor mapped we'll get a keyerror.
+  # we'll log the error but visually report the failure.
+  fail(log_msg: "Unmapped compression format #{filename}; #{e.message}")
 end
-dir = archive + "-dir"
-if File.exist?(dir)
-    FileUtils.rm_r(dir)
+
+data_location = `qtpaths --writable-path GenericDataLocation`.strip
+unless $?.success?
+  fail(log_msg: "Could not get GenericDataLocation #{data_location}")
 end
+servicedir = "#{data_location}/kservices5/ServiceMenus/"
+
+FileUtils.mkdir_p(servicedir) unless File.exist?(servicedir)
+if ARCHIVE.end_with?('.desktop')
+  puts 'Single-File Service-Menu'
+  puts ARCHIVE
+  puts servicedir
+  FileUtils.cp(ARCHIVE, servicedir)
+  exit
+end
+
+dir = "#{ARCHIVE}-dir"
+
+FileUtils.rm_r(dir) if File.exist?(dir)
 FileUtils.mkdir(dir)
-exit(-1) if !uncompress(archive, dir)
-# try: install-it.sh
-# try: install-it
-# try: installKDE4.sh
-# try: installKDE4
-# try: install.sh
-# try: install
-while true
-    dd = Dir.new(dir)
-    break if dd.count != 3
-    odir = dir
-    for entry in dd
-        dir += "/" + entry if entry != "." && entry != ".."
-    end
-    if !File.directory? dir
-        dir = odir
-        break
-    end
+
+fail(log_msg: 'uncompress failed') unless uncompress(ARCHIVE, dir)
+
+install_it = nil
+%w[install-it.sh install-it].find do |script|
+  install_it = Dir.glob("#{dir}/**/#{script}")[0]
+end
+
+installer = nil
+%w[installKDE4.sh installKDE4 install.sh install].find do |script|
+  installer = Dir.glob("#{dir}/**/#{script}")[0]
 end
-Dir.chdir(dir)
-def fail()
-    system("kdialog --passivepopup \"Installation failed\" 15")
-    exit(-1)
+
+Dir.chdir(dir) do
+  installed = false
+
+  [install_it, installer].uniq.compact.each { |f| File.chmod(0o700, f) }
+
+  if install_it
+    puts "[servicemenuinstallation]: Trying to run install_it #{install_it}"
+    installed = system(install_it)
+  elsif installer
+    puts "[servicemenuinstallation]: Trying to run installer #{installer}"
+    %w[--local --local-install --install].any? do |arg|
+      installed = system(installer, arg)
+    end
+  end
+
+  fail unless installed
 end
-if !((File.exist?(file = "./install-it.sh") || File.exist?(file = "./install-it")) && system(file))
-    fail() if !File.exist?(file = "./installKDE4.sh") && !File.exist?(file = "./installKDE4") && !File.exist?(file = "./install.sh") && !File.exist?(file = "./install")
-    File.new(file).chmod(0700)
-    fail() if !system(file + " --local") && !system(file + "--local-install") && !system(file + " --install")
-end    
diff --git a/src/settings/services/test/service_menu_deinstallation_test.rb b/src/settings/services/test/service_menu_deinstallation_test.rb
new file mode 100644 (file)
index 0000000..2b3514a
--- /dev/null
@@ -0,0 +1,121 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2019 Harald Sitter <sitter@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+require_relative 'test_helper'
+
+require 'tmpdir'
+
+class ServiceMenuDeinstallationTest < Test::Unit::TestCase
+  def setup
+    @tmpdir = Dir.mktmpdir("dolphintest-#{self.class.to_s.tr(':', '_')}")
+    @pwdir = Dir.pwd
+    Dir.chdir(@tmpdir)
+
+    ENV['XDG_DATA_HOME'] = File.join(@tmpdir, 'data')
+  end
+
+  def teardown
+    Dir.chdir(@pwdir)
+    FileUtils.rm_rf(@tmpdir)
+
+    ENV.delete('XDG_DATA_HOME')
+  end
+
+  def test_run_deinstall
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    archive_base = "#{service_dir}/foo.zip"
+    archive_dir = "#{archive_base}-dir/foo-1.1/"
+    FileUtils.mkpath(archive_dir)
+    File.write("#{archive_dir}/deinstall.sh", <<-DEINSTALL_SH)
+#!/bin/sh
+touch #{@tmpdir}/deinstall.sh-run
+    DEINSTALL_SH
+    File.write("#{archive_dir}/install.sh", <<-INSTALL_SH)
+#!/bin/sh
+touch #{@tmpdir}/install.sh-run
+    INSTALL_SH
+
+    assert(covered_system('servicemenudeinstallation', archive_base))
+
+    # deinstaller should be run
+    # installer should not be run
+    # archive_dir should have been correctly removed
+
+    assert_path_exist('deinstall.sh-run')
+    assert_path_not_exist('install.sh-run')
+    assert_path_not_exist(archive_dir)
+  end
+
+  def test_run_install_with_arg
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    archive_base = "#{service_dir}/foo.zip"
+    archive_dir = "#{archive_base}-dir/foo-1.1/"
+    FileUtils.mkpath(archive_dir)
+
+    File.write("#{archive_dir}/install.sh", <<-INSTALL_SH)
+#!/bin/sh
+if [ "$@" = "--uninstall" ]; then
+  touch #{@tmpdir}/install.sh-run
+  exit 0
+fi
+exit 1
+    INSTALL_SH
+
+    assert(covered_system('servicemenudeinstallation', archive_base))
+
+    assert_path_not_exist('deinstall.sh-run')
+    assert_path_exist('install.sh-run')
+    assert_path_not_exist(archive_dir)
+  end
+
+  # no scripts in sight
+  def test_run_fail
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    archive_base = "#{service_dir}/foo.zip"
+    archive_dir = "#{archive_base}-dir/foo-1.1/"
+    FileUtils.mkpath(archive_dir)
+
+    refute(covered_system('servicemenudeinstallation', archive_base))
+
+    # I am unsure if deinstallation really should keep the files around. But
+    # that's how it behaved originally so it's supposedly intentional
+    #   - sitter, 2019
+    assert_path_exist(archive_dir)
+  end
+
+  # For desktop files things are a bit special. There is one in .local/share/servicemenu-download
+  # and another in the actual ServiceMenus dir. The latter gets removed by the
+  # script, the former by KNS.
+  def test_run_desktop
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    downloaded_file = "#{service_dir}/foo.desktop"
+    FileUtils.mkpath(service_dir)
+    FileUtils.touch(downloaded_file)
+
+    menu_dir = "#{ENV['XDG_DATA_HOME']}/kservices5/ServiceMenus/"
+    installed_file = "#{menu_dir}/foo.desktop"
+    FileUtils.mkpath(menu_dir)
+    FileUtils.touch(installed_file)
+
+    assert(covered_system('servicemenudeinstallation', downloaded_file))
+
+    assert_path_exist(downloaded_file)
+    assert_path_not_exist(installed_file)
+  end
+end
diff --git a/src/settings/services/test/service_menu_installation_test.rb b/src/settings/services/test/service_menu_installation_test.rb
new file mode 100644 (file)
index 0000000..3c9fc90
--- /dev/null
@@ -0,0 +1,122 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2019 Harald Sitter <sitter@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+require_relative 'test_helper'
+
+require 'tmpdir'
+
+class ServiceMenuInstallationTest < Test::Unit::TestCase
+  def setup
+    @tmpdir = Dir.mktmpdir("dolphintest-#{self.class.to_s.tr(':', '_')}")
+    @pwdir = Dir.pwd
+    Dir.chdir(@tmpdir)
+
+    ENV['XDG_DATA_HOME'] = File.join(@tmpdir, 'data')
+  end
+
+  def teardown
+    Dir.chdir(@pwdir)
+    FileUtils.rm_rf(@tmpdir)
+
+    ENV.delete('XDG_DATA_HOME')
+  end
+
+  def test_run_install
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    FileUtils.mkpath(service_dir)
+    archive = "#{service_dir}/foo.tar"
+
+    archive_dir = 'foo' # relative so tar cf is relative without fuzz
+    FileUtils.mkpath(archive_dir)
+    File.write("#{archive_dir}/install-it.sh", <<-INSTALL_IT_SH)
+#!/bin/sh
+touch #{@tmpdir}/install-it.sh-run
+INSTALL_IT_SH
+    File.write("#{archive_dir}/install.sh", <<-INSTALL_SH)
+#!/bin/sh
+touch #{@tmpdir}/install.sh-run
+    INSTALL_SH
+    assert(system('tar', '-cf', archive, archive_dir))
+
+    assert(covered_system('servicemenuinstallation', archive))
+
+    tar_dir = "#{service_dir}/foo.tar-dir"
+    tar_extract_dir = "#{service_dir}/foo.tar-dir/foo"
+    assert_path_exist(tar_dir)
+    assert_path_exist(tar_extract_dir)
+    assert_path_exist("#{tar_extract_dir}/install-it.sh")
+    assert_path_exist("#{tar_extract_dir}/install.sh")
+  end
+
+  def test_run_install_with_arg
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    FileUtils.mkpath(service_dir)
+    archive = "#{service_dir}/foo.tar"
+
+    archive_dir = 'foo' # relative so tar cf is relative without fuzz
+    FileUtils.mkpath(archive_dir)
+    File.write("#{archive_dir}/install.sh", <<-INSTALL_SH)
+#!/bin/sh
+if [ "$@" = "--install" ]; then
+  touch #{@tmpdir}/install.sh-run
+  exit 0
+fi
+exit 1
+    INSTALL_SH
+    assert(system('tar', '-cf', archive, archive_dir))
+
+    assert(covered_system('servicemenuinstallation', archive))
+
+    tar_dir = "#{service_dir}/foo.tar-dir"
+    tar_extract_dir = "#{service_dir}/foo.tar-dir/foo"
+    assert_path_exist(tar_dir)
+    assert_path_exist(tar_extract_dir)
+    assert_path_not_exist("#{tar_extract_dir}/install-it.sh")
+    assert_path_exist("#{tar_extract_dir}/install.sh")
+  end
+
+  def test_run_fail
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    FileUtils.mkpath(service_dir)
+    archive = "#{service_dir}/foo.tar"
+
+    archive_dir = 'foo' # relative so tar cf is relative without fuzz
+    FileUtils.mkpath(archive_dir)
+    assert(system('tar', '-cf', archive, archive_dir))
+
+    refute(covered_system('servicemenuinstallation', archive))
+  end
+
+  def test_run_desktop
+    service_dir = File.join(Dir.pwd, 'share/servicemenu-download')
+    downloaded_file = "#{service_dir}/foo.desktop"
+    FileUtils.mkpath(service_dir)
+    FileUtils.touch(downloaded_file)
+
+    menu_dir = "#{ENV['XDG_DATA_HOME']}/kservices5/ServiceMenus/"
+    installed_file = "#{menu_dir}/foo.desktop"
+    FileUtils.mkpath(menu_dir)
+    FileUtils.touch(installed_file)
+
+    assert(covered_system('servicemenuinstallation', downloaded_file))
+
+    assert_path_exist(downloaded_file)
+    assert_path_exist(installed_file)
+  end
+end
diff --git a/src/settings/services/test/test_helper.rb b/src/settings/services/test/test_helper.rb
new file mode 100644 (file)
index 0000000..9da5cf3
--- /dev/null
@@ -0,0 +1,100 @@
+# Copyright (C) 2019 Harald Sitter <sitter@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+GLOBAL_COVERAGE_ROOT = File.dirname(__dir__) # ../
+
+# Simplecov is a bit meh and expects src and coverage to be under the
+# same root. Since we get run through cmake that assumption absolutely
+# doesn't hold true, so we'll need to figure out the coverage_dir relative
+# to the root and the root must always be the source :/
+# The relativity only works because internally the path gets expanded, this
+# isn't fully reliable, but oh well...
+# https://github.com/colszowka/simplecov/issues/716
+GLOBAL_COVERAGE_DIR = begin
+  require 'pathname'
+  src_path = Pathname.new(GLOBAL_COVERAGE_ROOT)
+  coverage_path = Pathname.new(File.join(Dir.pwd, 'coverage'))
+  coverage_path.relative_path_from(src_path).to_s
+end
+
+begin
+  require 'simplecov'
+
+  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
+    [
+      SimpleCov::Formatter::HTMLFormatter
+    ]
+  )
+
+  SimpleCov.start do
+    root GLOBAL_COVERAGE_ROOT
+    coverage_dir GLOBAL_COVERAGE_DIR
+  end
+rescue LoadError
+  warn 'SimpleCov not loaded'
+end
+
+# FIXME: add coverage report for jenkins?
+
+$LOAD_PATH.unshift(File.absolute_path('../', __dir__)) # ../
+
+def __test_method_name__
+  return @method_name if defined?(:@method_name)
+  index = 0
+  caller = ''
+  until caller.start_with?('test_')
+    caller = caller_locations(index, 1)[0].label
+    index += 1
+  end
+  caller
+end
+
+# system() variant which sets up merge-coverage. simplecov supports merging
+# of multiple coverage sets. we use this to get coverage metrics on the
+# binaries without having to refactor the script into runnable classes.
+def covered_system(cmd, *argv)
+  pid = fork do
+    Kernel.module_exec do
+      alias_method(:real_system, :system)
+      define_method(:system) do |*args|
+        return true if args.include?('kdialog') # disable kdialog call
+        real_system(*args)
+      end
+    end
+
+    begin
+      require 'simplecov'
+      SimpleCov.start do
+        root GLOBAL_COVERAGE_ROOT
+        coverage_dir GLOBAL_COVERAGE_DIR
+        command_name "#{cmd}_#{__test_method_name__}"
+      end
+    rescue LoadError
+      warn 'SimpleCov not loaded'
+    end
+
+    ARGV.replace(argv)
+    load "#{__dir__}/../#{cmd}"
+    puts 'all good, fork ending!'
+    exit 0
+  end
+  waitedpid, status = Process.waitpid2(pid)
+  assert_equal(pid, waitedpid)
+  status.success? # behave like system and return the success only
+end
+
+require 'test/unit'
diff --git a/src/settings/services/test/test_run.rb b/src/settings/services/test/test_run.rb
new file mode 100755 (executable)
index 0000000..b2149bb
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2019 Harald Sitter <sitter@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+# This is a fancy wrapper around test_helper to prevent the collector from
+# loading the helper twice as it would occur if we ran the helper directly.
+
+require_relative 'test_helper'
+
+Test::Unit::AutoRunner.run(true, File.absolute_path(__dir__))
index 07e4257a0becf6f9fb2a4b51619fe56dbebd1e6f..8ef20cb83b7bfc04f95164d6daa0cf1468de21a6 100644 (file)
@@ -3,6 +3,18 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
 find_package(Qt5Test CONFIG REQUIRED)
 include(ECMAddTests)
 
+include(FindGem)
+
+find_gem(test-unit REQUIRED)
+set_package_properties(Gem:test-unit PROPERTIES
+    DESCRIPTION "Ruby gem 'test-unit' required for testing of servicemenu helpers.")
+
+if(BUILD_COVERAGE)
+    find_gem(simplecov)
+    set_package_properties(Gem:simplecov PROPERTIES
+        DESCRIPTION "Ruby gem 'simplecov' used for coverage statistics.")
+endif()
+
 # KItemSetTest
 ecm_add_test(kitemsettest.cpp LINK_LIBRARIES dolphinprivate Qt5::Test)
 
@@ -69,3 +81,5 @@ ecm_add_test(placesitemmodeltest.cpp
 TEST_NAME placesitemmodeltest
 LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
 
+add_test(NAME servicemenutest
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../settings/services/test/test_run.rb)