diff --git a/lib/releaseme/translationunit.rb b/lib/releaseme/translationunit.rb index d6a21c6..0a86744 100644 --- a/lib/releaseme/translationunit.rb +++ b/lib/releaseme/translationunit.rb @@ -1,195 +1,194 @@ #-- # Copyright (C) 2007-2017 Harald Sitter # # 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) version 3 or any later version # accepted by the membership of KDE e.V. (or its successor approved # by the membership of KDE e.V.), which shall act as a proxy # defined in Section 14 of version 3 of the license. # # 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, see . #++ require 'thread' require_relative 'origin' require_relative 'source' require_relative 'svn' require_relative 'tmpdir' # Base class for a {Source} that represents a translation unit. This notibly # are either message translations as obtained by {L10n} or documentation # translations as obtained by {Documentation}. module ReleaseMe class TranslationUnit < Source # The VCS to use to obtain the l10n sources attr_reader :vcs # The type of the release (stable,trunk) attr_reader :type # The i18n base path to use in SVN (e.g. extragear-utils/) attr_reader :i18n_path # Found templates attr_reader :templates # The project name this translation belongs to attr_reader :project_name # @deprecated use a {Origin} TRUNK = Origin::TRUNK # @deprecated use a {Origin} STABLE = Origin::STABLE # @deprecated use a {Origin} LTS = Origin::LTS # Languages that will by default be dropped from the list of languages # obtained from SVN. DEFAULT_EXCLUDED_LANGUAGES = %w[x-test].freeze # anonsvn only allows 5 concurrent connections. THREAD_COUNT = 5 - def initialize(type, project_name, i18n_path) + def initialize(type, project_name, i18n_path, vcs: Svn.new) @type = type @i18n_path = i18n_path @project_name = project_name - - @vcs = Svn.new + @vcs = vcs @languages = [] @default_excluded_languages = nil @templates = [] validate_instace_variables init_repo_url(ENV.fetch('RELEASEME_SVN_REPO_URL', 'svn://anonsvn.kde.org/home/kde/')) end # @return Array list of excluded languages, defaults to # class const {DEFAULT_EXCLUDED_LANGUAGES} def default_excluded_languages @default_excluded_languages || DEFAULT_EXCLUDED_LANGUAGES end attr_writer :default_excluded_languages # FIXME: this name seems a bit meh def init_repo_url(base_url) repo_url = base_url repo_url += "/#{url_type_suffix}/#{url_l10n_dir}/" @vcs.repository = repo_url end def languages(excluded = []) excluded.concat(default_excluded_languages) languages = self.class.languages(@vcs).clone # do not modify the live list languages.delete_if { |l| excluded.include?(l) } end def languages_queue(excluded = nil, without: []) queue = Queue.new languages(excluded || without).each { |l| queue << l } queue end # FIXME: should we just go full abstract and forget about the specifics # factory? # def vcs_l10n_path(lang) # fail 'todo' # end # # def get(source_dir) # fail 'todo' # end # FIXME: not tested def self.languages(vcs) # Cache this bugger to avoid double lookup for messages and documentation. # NOTE: this only is reasonable for as long as all derivaed classes have # the same vcs configuration, so this is potentially dangerous. @languages ||= vcs.cat('subdirs').split($RS) end def self.languages=(l) @languages = l end private def blocking_thread_pool threads = Array.new(THREAD_COUNT) do Thread.new do Thread.current.abort_on_exception = true yield end end threads.each(&:join) end def each_language_with_tmpdir(queue = languages_queue) blocking_thread_pool do until queue.empty? begin lang = queue.pop(true) rescue ThreadError # When pop runs into an empty queue with non_block=true it raises # an exception. We'll simply continue with it as our loop should # naturally end anyway. continue end ReleaseMe.mktmpdir(self.class.to_s) { |tmpdir| yield lang, tmpdir } end end end def url_type_suffix case type when Origin::TRUNK, Origin::TRUNK_KDE4 'trunk' when Origin::STABLE, Origin::LTS, Origin::STABLE_KDE4 'branches/stable' else raise "Unknown l10n type #{type}" end end # special translations for Plasma LTS def url_l10n_dir case type when Origin::TRUNK, Origin::STABLE return 'l10n-kf5' when Origin::LTS return url_l10n_dir_lts when Origin::TRUNK_KDE4, Origin::STABLE_KDE4 return 'l10n-kde4' end # FIXME: move the concept of origins to project and make an Array # Then blanket assert the type validity in #init raise "Unknown l10n type #{type}" end # LTS is special in that they are about as generic as a hardcoded hardon. # Unless we can manually map the LTS origin to a directory it is unreleaseable # as we effectively do not know what LTS means for the given product. # Since we have no access to higher level data this is derived from i18n_path. def url_l10n_dir_lts return 'l10n-kf5-plasma-lts' if i18n_path == 'kde-workspace' raise "Unknown lts type for path #{i18n_path}." end def validate_instace_variables raise 'type must not be nil' unless @type raise 'i18n_path must not be nil' unless @i18n_path raise 'project_name must not be nil' unless @project_name end end end diff --git a/test/translationunit_test.rb b/test/translationunit_test.rb index 7ad7c23..86be0a2 100644 --- a/test/translationunit_test.rb +++ b/test/translationunit_test.rb @@ -1,119 +1,142 @@ require_relative 'lib/testme' require_relative '../lib/releaseme/translationunit' class TestTranslationUnit < Testme def setup # Disable querying VCS by default. ReleaseMe::TranslationUnit.languages = [] end def create(type) - l = ReleaseMe::TranslationUnit.new(type, 'amarok', File::NULL) + @svn = mock('svn') + @svn.stubs(:cat).with('subdirs').returns("de\nx-test\n") + + # mock an attr + @repository = '' + @svn.stubs(:repository=).with do |v| + @repository.replace(v) + true + end + @svn.stubs(:repository).returns(@repository) + + l = ReleaseMe::TranslationUnit.new(type, 'amarok', File::NULL, vcs: @svn) l.target = "#{@dir}/l10n" l end def create_plasma(type) - l = ReleaseMe::TranslationUnit.new(type, 'khotkeys', 'kde-workspace') + @svn = mock('svn') + @svn.stubs(:cat).with('subdirs').returns("de\nx-test\n") + + # mock an attr + @repository = '' + @svn.stubs(:repository=).with do |v| + @repository.replace(v) + true + end + @svn.stubs(:repository).returns(@repository) + + l = ReleaseMe::TranslationUnit.new(type, 'khotkeys', 'kde-workspace', + vcs: @svn) l.target = "#{@dir}/l10n" l end def create_trunk create(ReleaseMe::TranslationUnit::TRUNK) end def create_stable create(ReleaseMe::TranslationUnit::STABLE) end def create_lts create(ReleaseMe::TranslationUnit::LTS) end def create_lts_plasma create_plasma(ReleaseMe::TranslationUnit::LTS) end def test_0_attr l = create_trunk assert_equal("#{@dir}/l10n", l.target) assert_equal(ReleaseMe::TranslationUnit::TRUNK, l.type) assert_equal(File::NULL, l.i18n_path) end def test_0_repo_url_init_trunk l = create_trunk assert_equal(ReleaseMe::TranslationUnit::TRUNK, l.type) l.init_repo_url('file://a') assert_equal('file://a/trunk/l10n-kf5/', l.vcs.repository) end def test_0_repo_url_init_stable l = create_stable assert_equal(ReleaseMe::TranslationUnit::STABLE, l.type) l.init_repo_url('file://a') assert_equal(l.vcs.repository, 'file://a/branches/stable/l10n-kf5/') end # LTS translations should be used but only for Plasma repos def test_0_repo_url_init_lts assert_raises do create_lts end end def test_0_repo_url_init_lts_plasma l = create_lts_plasma assert_equal(ReleaseMe::TranslationUnit::LTS, l.type) l.init_repo_url('file://a') assert_equal(l.vcs.repository, 'file://a/branches/stable/l10n-kf5-plasma-lts/') end def test_invalid_inits assert_raises do ReleaseMe::TranslationUnit.new(nil, 'amarok', File::NULL) end assert_raises do ReleaseMe::TranslationUnit.new(ReleaseMe::TranslationUnit::TRUNK, nil, 'null') end assert_raises do ReleaseMe::TranslationUnit.new(ReleaseMe::TranslationUnit::TRUNK, 'amarok', nil) end end def test_invalid_type assert_raises do # :fishyfishy is a bad type and can't be mapped to a repo path ReleaseMe::TranslationUnit.new(:fishyfishy, 'amarok', File::NULL) end end def test_simple_kde4 # Technically we could handle kde4, given this is a fairly low level class # we may just get away with this. u = ReleaseMe::TranslationUnit.new(ReleaseMe::Origin::TRUNK_KDE4, 'amarok', File::NULL) assert_equal('svn://anonsvn.kde.org/home/kde//trunk/l10n-kde4/', u.vcs.repository) end def test_default_exclusion ReleaseMe::TranslationUnit.languages = nil # force detection u = create_trunk langs = u.languages refute_includes(langs, 'x-test') refute(langs.empty?) end def test_exclusion ReleaseMe::TranslationUnit.languages = nil # force detection u = create_trunk u.default_excluded_languages = [] assert_includes(u.languages, 'x-test') # Make sure the exclusion list is not cached so it can be changed later. u.default_excluded_languages = nil refute_includes(u.languages, 'x-test') end end