Skip to content

Commit

Permalink
Merge 4f636d4 into 933bd28
Browse files Browse the repository at this point in the history
  • Loading branch information
teclator committed Jul 23, 2018
2 parents 933bd28 + 4f636d4 commit caac21c
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 94 deletions.
113 changes: 28 additions & 85 deletions library/types/src/modules/Punycode.rb
Expand Up @@ -30,17 +30,18 @@
# $Id$
#
require "yast"
require "simpleidn"

module Yast
class PunycodeClass < Module
# string, matching this regexp, is not cached
NOT_CACHED_REGEXP = /^[0123456789.]*$/

def main
textdomain "base"

@tmp_dir = nil

# string, matching this regexp, is not cached
@not_cached_regexp = "^[0123456789.]*$"

#
# Encoded string in cache has the same index
# as its Decoded format in the second list.
Expand Down Expand Up @@ -124,9 +125,7 @@ def GetEncodedCachedString(decoded_string)
ret = nil

# numbers and empty strings are not converted
if Builtins.regexpmatch(decoded_string, @not_cached_regexp)
return decoded_string
end
return decoded_string if NOT_CACHED_REGEXP.match(decoded_string)

counter = -1
# searching through decoded strings to find the index
Expand All @@ -151,9 +150,7 @@ def GetDecodedCachedString(encoded_string)
ret = nil

# numbers and empty strings are not converted
if Builtins.regexpmatch(encoded_string, @not_cached_regexp)
return encoded_string
end
return encoded_string if NOT_CACHED_REGEXP.match(encoded_string)

counter = -1
# searching through encoded strings to find the index
Expand Down Expand Up @@ -183,105 +180,51 @@ def GetTmpDirectory
# format. Unicode to Punycode or Punycode to Unicode (param to_punycode).
# It uses a cache of already-converted strings.
def ConvertBackAndForth(strings_in, to_punycode)
strings_in = deep_copy(strings_in)
# list of returned strings
strings_out = []

# Some (or maybe all) strings needn't be cached
not_cached = []

# Check the cache for already entered strings
current_index = -1
test_cached = Builtins.listmap(strings_in) do |string_in|
test_cached = strings_in.each_with_object({}) do |string_in, all|
# Numbers, IPs and empty strings are not converted
string_out = if Builtins.regexpmatch(string_in, @not_cached_regexp)
string_in
elsif to_punycode
GetEncodedCachedString(string_in)
else
GetDecodedCachedString(string_in)
end
string_out =
if NOT_CACHED_REGEXP.match(string_in)
string_in
elsif to_punycode
GetEncodedCachedString(string_in)
else
GetDecodedCachedString(string_in)
end

if string_out.nil?
current_index = Ops.add(current_index, 1)
Ops.set(not_cached, current_index, string_in)
end
{ string_in => string_out }
not_cached << string_in if string_out.nil?
all[string_in] = string_out
end

converted_not_cached = []

# There is something not cached, converting them at once
if not_cached != []
tmp_in = Ops.add(GetTmpDirectory(), "/tmp-idnconv-in.ycp")
tmp_out = Ops.add(GetTmpDirectory(), "/tmp-idnconv-out.ycp")

SCR.Write(path(".target.ycp"), tmp_in, not_cached)
convert_command = Builtins.sformat(
"/usr/bin/idnconv %1 %2 > %3",
to_punycode ? "" : "-reverse",
tmp_in,
tmp_out
)

if Convert.to_integer(
SCR.Execute(path(".target.bash"), convert_command)
) != 0
Builtins.y2error("Conversion failed!")
else
converted_not_cached = Convert.convert(
SCR.Read(path(".target.ycp"), tmp_out),
from: "any",
to: "list <string>"
)
# Parsing the YCP file failed
if converted_not_cached.nil?
Builtins.y2error(
"Erroneous YCP file: %1",
SCR.Read(path(".target.string"), tmp_out)
)
end
end
if !not_cached.empty?
meth = to_punycode ? :to_ascii : :to_unicode
converted_not_cached = not_cached.map { |v| SimpleIDN.public_send(meth, v) }
end

# Listing through the given list and adjusting the return list
current_index = -1
found_index = -1
Builtins.foreach(strings_in) do |string_in|
current_index = Ops.add(current_index, 1)
strings_in.each_with_object([]) do |string_in, all|
# Already cached string
if !Ops.get(test_cached, string_in).nil?
Ops.set(
strings_out,
current_index,
Ops.get(test_cached, string_in, "")
)

# Recently converted strings
else
found_index = Ops.add(found_index, 1)
Ops.set(
strings_out,
current_index,
Ops.get(converted_not_cached, found_index, "")
)
if test_cached[string_in]
all << test_cached[string_in]
else # Recently converted strings
found_index += 1
all << converted_not_cached[found_index] || ""

# Adding converted strings to cache
if to_punycode
CreateNewCacheRecord(
string_in,
Ops.get(converted_not_cached, found_index, "")
)
CreateNewCacheRecord(string_in, converted_not_cached[found_index] || "")
else
CreateNewCacheRecord(
Ops.get(converted_not_cached, found_index, ""),
string_in
)
CreateNewCacheRecord(converted_not_cached[found_index] || "", string_in)
end
end
end

deep_copy(strings_out)
end

# Converts list of UTF-8 strings into their Punycode
Expand Down
4 changes: 3 additions & 1 deletion library/types/test/Makefile.am
Expand Up @@ -2,8 +2,10 @@ TESTS = \
ip_test.rb \
ipv4_netmask_test.rb \
hostname_test.rb \
punycode_test.rb \
string_test.rb \
url_test.rb \
string_test.rb
urlrecode_test.rb

TEST_EXTENSIONS = .rb
RB_LOG_COMPILER = rspec
Expand Down
113 changes: 113 additions & 0 deletions library/types/test/punycode_test.rb
@@ -0,0 +1,113 @@
#!/usr/bin/env rspec
# encoding: utf-8
#
# Copyright (c) [2018] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# 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, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require_relative "./test_helper"
Yast.import "Punycode"

describe Yast::Punycode do
subject(:punycode) { Yast::Punycode }

IP = "192.168.122.1".freeze
NUMBER = "15".freeze

before do
punycode.main # reset the cache
end

describe "#ConvertBackAndForth" do
context "when converting to Punycode" do
it "returns all strings converted to Punycode" do
expect(punycode.ConvertBackAndForth(["españa"], true)).to eq(["xn--espaa-rta"])
end

it "caches converted values" do
expect(punycode).to receive(:CreateNewCacheRecord).with("españa", "xn--espaa-rta")
punycode.ConvertBackAndForth(["españa"], true)
end

context "when the string is cached" do
before do
allow(subject).to receive(:GetEncodedCachedString).with("españa")
.and_return("cached_value")
end

it "returns the cached value" do
expect(punycode.ConvertBackAndForth(["españa"], true)).to eq(["cached_value"])
end
end
end

context "when converting to UTF-8" do
it "returns all strings converted to UTF-8" do
expect(punycode.ConvertBackAndForth(["xn--espaa-rta"], false)).to eq(["españa"])
end

it "caches converted values" do
expect(punycode).to receive(:CreateNewCacheRecord).with("españa", "xn--espaa-rta")
punycode.ConvertBackAndForth(["xn--espaa-rta"], false)
end

context "when the string is cached" do
before do
allow(subject).to receive(:GetDecodedCachedString).with("xn--espaa-rta")
.and_return("cached_value")
end

it "returns the cached value" do
expect(punycode.ConvertBackAndForth(["xn--espaa-rta"], false)).to eq(["cached_value"])
end
end
end

context "when an IP address is given" do
it "is not converted" do
expect(punycode.ConvertBackAndForth([IP], true)).to eq([IP])
end
end

context "when a string representing a number is given" do
it "is not converted" do
expect(punycode.ConvertBackAndForth([NUMBER], true)).to eq([NUMBER])
end
end

context "when an empty string is given" do
it "is not converted" do
expect(punycode.ConvertBackAndForth([""], true)).to eq([""])
end
end
end

describe "#EncodePunycodes" do
it "returns strings converted to punycode ignoring numbers, IP addresses and empty strings" do
punycodes = punycode.EncodePunycodes(["españa", NUMBER, IP, ""])
expect(punycodes).to eq(["xn--espaa-rta", NUMBER, IP, ""])
end
end

describe "#DecodePunycodes" do
it "returns strings converted to unicode ignoring numbers, IP addresses and empty strings" do
punycodes = punycode.DecodePunycodes(["xn--espaa-rta", NUMBER, IP, ""])
expect(punycodes).to eq(["españa", NUMBER, IP, ""])
end
end
end
7 changes: 7 additions & 0 deletions package/yast2.changes
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Mon Jul 23 09:07:05 UTC 2018 - knut.anderssen@suse.com

- Backported the replacement of idnconv with simpleidn library
(bsc#1101851)
- 3.2.47

-------------------------------------------------------------------
Tue Jul 3 08:01:07 UTC 2018 - knut.anderssen@suse.com

Expand Down
13 changes: 5 additions & 8 deletions package/yast2.spec
Expand Up @@ -17,7 +17,7 @@


Name: yast2
Version: 3.2.46
Version: 3.2.47
Release: 0
Summary: YaST2 - Main Package
License: GPL-2.0
Expand All @@ -39,6 +39,8 @@ BuildRequires: rubygem(%{rb_default_ruby_abi}:cheetah)
BuildRequires: update-desktop-files
# For running RSpec tests during build
BuildRequires: rubygem(%{rb_default_ruby_abi}:rspec)
# For converting to/from punycode strings
BuildRequires: rubygem(%{rb_default_ruby_abi}:simpleidn)
# Needed already in build time
BuildRequires: yast2-core >= 2.18.12
BuildRequires: yast2-devtools >= 3.1.10
Expand Down Expand Up @@ -66,6 +68,8 @@ Requires: perl-XML-Simple
Requires: rubygem(%{rb_default_ruby_abi}:abstract_method)
# for file access using augeas
Requires: rubygem(%{rb_default_ruby_abi}:cfa)
# For converting to/from punycode strings
Requires: rubygem(%{rb_default_ruby_abi}:simpleidn)
Requires: sysconfig >= 0.80.0
# for running scripts
Requires: rubygem(%{rb_default_ruby_abi}:cheetah)
Expand Down Expand Up @@ -96,13 +100,6 @@ Conflicts: yast2-mail < 3.1.7
# Older packager use removed API
Conflicts: yast2-packager < 3.1.34
BuildRoot: %{_tmppath}/%{name}-%{version}-build
# for Punycode.rb (bnc#651893) - the idnconv tool is located in
# different packages (SLE12/Leap-42.1: bind-utils, TW/Factory: idnkit)
%if 0%{?suse_version} >= 1330
Requires: idnkit
%else
Requires: bind-utils
%endif
Obsoletes: yast2-devel-doc
# for the PackageExtractor class, just make sure they are present,
# these should be present even in a very minimal installation
Expand Down

0 comments on commit caac21c

Please sign in to comment.