Merge pull request #906 from reitermarkus/os-language
Make `MacOS.language` less opinionated and add `language` stanza.
This commit is contained in:
commit
35ee283108
@ -1,6 +1,23 @@
|
||||
module Hbc
|
||||
class Auditor
|
||||
def self.audit(cask, audit_download: false, check_token_conflicts: false)
|
||||
saved_languages = MacOS.instance_variable_get(:@languages)
|
||||
|
||||
if languages_blocks = cask.instance_variable_get(:@dsl).instance_variable_get(:@language_blocks)
|
||||
languages_blocks.keys.each do |languages|
|
||||
ohai "Auditing language: #{languages.map { |lang| "'#{lang}'" }.join(", ")}"
|
||||
MacOS.instance_variable_set(:@languages, languages)
|
||||
audit_cask_instance(Hbc.load(cask.sourcefile_path), audit_download, check_token_conflicts)
|
||||
CLI::Cleanup.run(cask.token) if audit_download
|
||||
end
|
||||
else
|
||||
audit_cask_instance(cask, audit_download, check_token_conflicts)
|
||||
end
|
||||
ensure
|
||||
MacOS.instance_variable_set(:@languages, saved_languages)
|
||||
end
|
||||
|
||||
def self.audit_cask_instance(cask, audit_download, check_token_conflicts)
|
||||
download = audit_download && Download.new(cask)
|
||||
audit = Audit.new(cask, download: download,
|
||||
check_token_conflicts: check_token_conflicts)
|
||||
|
||||
@ -11,7 +11,10 @@ module Hbc
|
||||
@token = token
|
||||
@sourcefile_path = sourcefile_path
|
||||
@dsl = dsl || DSL.new(@token)
|
||||
@dsl.instance_eval(&block) if block_given?
|
||||
if block_given?
|
||||
@dsl.instance_eval(&block)
|
||||
@dsl.language_eval
|
||||
end
|
||||
end
|
||||
|
||||
DSL::DSL_METHODS.each do |method_name|
|
||||
|
||||
@ -179,6 +179,10 @@ module Hbc
|
||||
def self.parser
|
||||
# If you modify these arguments, please update USAGE.md
|
||||
@parser ||= OptionParser.new do |opts|
|
||||
opts.on("--language STRING") do
|
||||
# handled in OS::Mac
|
||||
end
|
||||
|
||||
OPTIONS.each do |option, method|
|
||||
opts.on("#{option}" "PATH", Pathname) do |path|
|
||||
Hbc.public_send(method, path)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
require "set"
|
||||
require "locale"
|
||||
|
||||
require "hbc/dsl/appcast"
|
||||
require "hbc/dsl/base"
|
||||
@ -64,6 +65,7 @@ module Hbc
|
||||
:depends_on,
|
||||
:gpg,
|
||||
:homepage,
|
||||
:language,
|
||||
:license,
|
||||
:name,
|
||||
:sha256,
|
||||
@ -98,6 +100,43 @@ module Hbc
|
||||
@homepage ||= homepage
|
||||
end
|
||||
|
||||
def language(*args, default: false, &block)
|
||||
if !args.empty? && block_given?
|
||||
@language_blocks ||= {}
|
||||
@language_blocks[args] = block
|
||||
|
||||
return unless default
|
||||
|
||||
unless @language_blocks.default.nil?
|
||||
raise CaskInvalidError.new(token, "Only one default language may be defined")
|
||||
end
|
||||
|
||||
@language_blocks.default = block
|
||||
else
|
||||
language_eval
|
||||
end
|
||||
end
|
||||
|
||||
def language_eval
|
||||
return @language if instance_variable_defined?(:@language)
|
||||
|
||||
if @language_blocks.nil? || @language_blocks.empty?
|
||||
return @language = nil
|
||||
end
|
||||
|
||||
MacOS.languages.map(&Locale.method(:parse)).each do |locale|
|
||||
key = @language_blocks.keys.detect { |strings|
|
||||
strings.any? { |string| locale.include?(string) }
|
||||
}
|
||||
|
||||
next if key.nil?
|
||||
|
||||
return @language = @language_blocks[key].call
|
||||
end
|
||||
|
||||
@language = @language_blocks.default.call
|
||||
end
|
||||
|
||||
def url(*args, &block)
|
||||
url_given = !args.empty? || block_given?
|
||||
return @url unless url_given
|
||||
|
||||
@ -8,7 +8,7 @@ module Hbc
|
||||
@command = command
|
||||
end
|
||||
|
||||
def_delegators :@cask, :token, :version, :caskroom_path, :staged_path, :appdir
|
||||
def_delegators :@cask, :token, :version, :caskroom_path, :staged_path, :appdir, :language
|
||||
|
||||
def system_command(executable, options = {})
|
||||
@command.run!(executable, options)
|
||||
|
||||
72
Library/Homebrew/cask/spec/locale_spec.rb
Normal file
72
Library/Homebrew/cask/spec/locale_spec.rb
Normal file
@ -0,0 +1,72 @@
|
||||
require "spec_helper"
|
||||
require "locale"
|
||||
|
||||
describe Locale do
|
||||
describe "::parse" do
|
||||
it "parses a string in the correct format" do
|
||||
expect(described_class.parse("zh")).to eql(described_class.new("zh", nil, nil))
|
||||
expect(described_class.parse("zh-CN")).to eql(described_class.new("zh", "CN", nil))
|
||||
expect(described_class.parse("zh-Hans")).to eql(described_class.new("zh", nil, "Hans"))
|
||||
expect(described_class.parse("zh-CN-Hans")).to eql(described_class.new("zh", "CN", "Hans"))
|
||||
end
|
||||
|
||||
context "raises a ParserError when given" do
|
||||
it "an empty string" do
|
||||
expect{ described_class.parse("") }.to raise_error(Locale::ParserError)
|
||||
end
|
||||
|
||||
it "a string in a wrong format" do
|
||||
expect { described_class.parse("zh_CN_Hans") }.to raise_error(Locale::ParserError)
|
||||
expect { described_class.parse("zhCNHans") }.to raise_error(Locale::ParserError)
|
||||
expect { described_class.parse("zh-CN_Hans") }.to raise_error(Locale::ParserError)
|
||||
expect { described_class.parse("zhCN") }.to raise_error(Locale::ParserError)
|
||||
expect { described_class.parse("zh_Hans") }.to raise_error(Locale::ParserError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "::new" do
|
||||
it "raises an ArgumentError when all arguments are nil" do
|
||||
expect { described_class.new(nil, nil, nil) }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "raises a ParserError when one of the arguments does not match the locale format" do
|
||||
expect { described_class.new("ZH", nil, nil) }.to raise_error(Locale::ParserError)
|
||||
expect { described_class.new(nil, "cn", nil) }.to raise_error(Locale::ParserError)
|
||||
expect { described_class.new(nil, nil, "hans") }.to raise_error(Locale::ParserError)
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new("zh", "CN", "Hans") }
|
||||
|
||||
describe "#include?" do
|
||||
it { is_expected.to include("zh") }
|
||||
it { is_expected.to include("zh-CN") }
|
||||
it { is_expected.to include("CN") }
|
||||
it { is_expected.to include("CN-Hans") }
|
||||
it { is_expected.to include("Hans") }
|
||||
it { is_expected.to include("zh-CN-Hans") }
|
||||
end
|
||||
|
||||
describe "#eql?" do
|
||||
subject { described_class.new("zh", "CN", "Hans") }
|
||||
|
||||
context "all parts match" do
|
||||
it { is_expected.to eql("zh-CN-Hans") }
|
||||
it { is_expected.to eql(subject) }
|
||||
end
|
||||
|
||||
context "only some parts match" do
|
||||
it { is_expected.to_not eql("zh") }
|
||||
it { is_expected.to_not eql("zh-CN") }
|
||||
it { is_expected.to_not eql("CN") }
|
||||
it { is_expected.to_not eql("CN-Hans") }
|
||||
it { is_expected.to_not eql("Hans") }
|
||||
end
|
||||
|
||||
it "does not raise if 'other' cannot be parsed" do
|
||||
expect { subject.eql?("zh_CN_Hans") }.not_to raise_error
|
||||
expect(subject.eql?("zh_CN_Hans")).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -122,6 +122,56 @@ describe Hbc::DSL do
|
||||
end
|
||||
end
|
||||
|
||||
describe "language stanza" do
|
||||
it "allows multilingual casks" do
|
||||
cask = lambda do
|
||||
Hbc::Cask.new("cask-with-apps") do
|
||||
language "zh" do
|
||||
sha256 "abc123"
|
||||
"zh-CN"
|
||||
end
|
||||
|
||||
language "en-US", default: true do
|
||||
sha256 "xyz789"
|
||||
"en-US"
|
||||
end
|
||||
|
||||
url "https://example.org/#{language}.zip"
|
||||
end
|
||||
end
|
||||
|
||||
MacOS.stubs(languages: ["zh"])
|
||||
cask.call.language.must_equal "zh-CN"
|
||||
cask.call.sha256.must_equal "abc123"
|
||||
cask.call.url.to_s.must_equal "https://example.org/zh-CN.zip"
|
||||
|
||||
MacOS.stubs(languages: ["zh-XX"])
|
||||
cask.call.language.must_equal "zh-CN"
|
||||
cask.call.sha256.must_equal "abc123"
|
||||
cask.call.url.to_s.must_equal "https://example.org/zh-CN.zip"
|
||||
|
||||
MacOS.stubs(languages: ["en"])
|
||||
cask.call.language.must_equal "en-US"
|
||||
cask.call.sha256.must_equal "xyz789"
|
||||
cask.call.url.to_s.must_equal "https://example.org/en-US.zip"
|
||||
|
||||
MacOS.stubs(languages: ["xx-XX"])
|
||||
cask.call.language.must_equal "en-US"
|
||||
cask.call.sha256.must_equal "xyz789"
|
||||
cask.call.url.to_s.must_equal "https://example.org/en-US.zip"
|
||||
|
||||
MacOS.stubs(languages: ["xx-XX", "zh", "en"])
|
||||
cask.call.language.must_equal "zh-CN"
|
||||
cask.call.sha256.must_equal "abc123"
|
||||
cask.call.url.to_s.must_equal "https://example.org/zh-CN.zip"
|
||||
|
||||
MacOS.stubs(languages: ["xx-XX", "en-US", "zh"])
|
||||
cask.call.language.must_equal "en-US"
|
||||
cask.call.sha256.must_equal "xyz789"
|
||||
cask.call.url.to_s.must_equal "https://example.org/en-US.zip"
|
||||
end
|
||||
end
|
||||
|
||||
describe "app stanza" do
|
||||
it "allows you to specify app stanzas" do
|
||||
cask = Hbc::Cask.new("cask-with-apps") do
|
||||
|
||||
68
Library/Homebrew/locale.rb
Normal file
68
Library/Homebrew/locale.rb
Normal file
@ -0,0 +1,68 @@
|
||||
class Locale
|
||||
class ParserError < ::RuntimeError
|
||||
end
|
||||
|
||||
LANGUAGE_REGEX = /(?:[a-z]{2})/
|
||||
REGION_REGEX = /(?:[A-Z]{2})/
|
||||
SCRIPT_REGEX = /(?:[A-Z][a-z]{3})/
|
||||
|
||||
LOCALE_REGEX = /^(#{LANGUAGE_REGEX})?(?:(?:^|-)(#{REGION_REGEX}))?(?:(?:^|-)(#{SCRIPT_REGEX}))?$/
|
||||
|
||||
def self.parse(string)
|
||||
language, region, script = string.to_s.scan(LOCALE_REGEX)[0]
|
||||
|
||||
if language.nil? && region.nil? && script.nil?
|
||||
raise ParserError, "'#{string}' cannot be parsed to a #{self.class}"
|
||||
end
|
||||
|
||||
new(language, region, script)
|
||||
end
|
||||
|
||||
attr_reader :language, :region, :script
|
||||
|
||||
def initialize(language, region, script)
|
||||
if language.nil? && region.nil? && script.nil?
|
||||
raise ArgumentError, "#{self.class} cannot be empty"
|
||||
end
|
||||
|
||||
{
|
||||
language: language,
|
||||
region: region,
|
||||
script: script,
|
||||
}.each do |key, value|
|
||||
next if value.nil?
|
||||
|
||||
regex = self.class.const_get("#{key.upcase}_REGEX")
|
||||
raise ParserError, "'#{value}' does not match #{regex}" unless value =~ regex
|
||||
instance_variable_set(:"@#{key}", value)
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def include?(other)
|
||||
other = self.class.parse(other) unless other.is_a?(self.class)
|
||||
|
||||
[:language, :region, :script].all? { |var|
|
||||
if other.public_send(var).nil?
|
||||
true
|
||||
else
|
||||
public_send(var) == other.public_send(var)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
other = self.class.parse(other) unless other.is_a?(self.class)
|
||||
[:language, :region, :script].all? { |var|
|
||||
public_send(var) == other.public_send(var)
|
||||
}
|
||||
rescue ParserError
|
||||
false
|
||||
end
|
||||
alias == eql?
|
||||
|
||||
def to_s
|
||||
[@language, @region, @script].compact.join("-")
|
||||
end
|
||||
end
|
||||
@ -41,8 +41,24 @@ module OS
|
||||
version.to_sym
|
||||
end
|
||||
|
||||
def languages
|
||||
return @languages unless @languages.nil?
|
||||
|
||||
@languages = Utils.popen_read("defaults", "read", ".GlobalPreferences", "AppleLanguages").scan(/[^ \n"(),]+/)
|
||||
|
||||
if ENV["HOMEBREW_LANGUAGES"]
|
||||
@languages = ENV["HOMEBREW_LANGUAGES"].split(",") + @languages
|
||||
end
|
||||
|
||||
if ARGV.value("language")
|
||||
@languages = ARGV.value("language").split(",") + @languages
|
||||
end
|
||||
|
||||
@languages = @languages.uniq
|
||||
end
|
||||
|
||||
def language
|
||||
@language ||= Utils.popen_read("defaults", "read", ".GlobalPreferences", "AppleLanguages").delete(" \n\"()").sub(/,.*/, "")
|
||||
languages.first
|
||||
end
|
||||
|
||||
def active_developer_dir
|
||||
|
||||
@ -2,7 +2,15 @@ require "testing_env"
|
||||
require "os/mac"
|
||||
|
||||
class OSMacLanguageTests < Homebrew::TestCase
|
||||
LANGUAGE_REGEX = /\A[a-z]{2}(-[A-Z]{2})?(-[A-Z][a-z]{3})?\Z/
|
||||
|
||||
def test_languages_format
|
||||
OS::Mac.languages.each do |language|
|
||||
assert_match LANGUAGE_REGEX, language
|
||||
end
|
||||
end
|
||||
|
||||
def test_language_format
|
||||
assert_match(/\A[a-z]{2}(-[A-Z]{2})?\Z/, OS::Mac.language)
|
||||
assert_match LANGUAGE_REGEX, OS::Mac.language
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user