travis-yaml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +14 -0
  5. data/Gemfile +9 -0
  6. data/Gemfile.lock +73 -0
  7. data/LICENSE +22 -0
  8. data/README.md +232 -0
  9. data/Rakefile +3 -0
  10. data/SPEC.md +1018 -0
  11. data/bench/parser_bench.rb +54 -0
  12. data/config.ru +2 -0
  13. data/lib/travis/yaml.rb +43 -0
  14. data/lib/travis/yaml/matrix.rb +65 -0
  15. data/lib/travis/yaml/nodes.rb +40 -0
  16. data/lib/travis/yaml/nodes/branches.rb +12 -0
  17. data/lib/travis/yaml/nodes/bundler_args.rb +6 -0
  18. data/lib/travis/yaml/nodes/cache.rb +29 -0
  19. data/lib/travis/yaml/nodes/compiler.rb +7 -0
  20. data/lib/travis/yaml/nodes/compiler_entry.rb +9 -0
  21. data/lib/travis/yaml/nodes/deploy.rb +7 -0
  22. data/lib/travis/yaml/nodes/deploy_conditions.rb +12 -0
  23. data/lib/travis/yaml/nodes/deploy_entry.rb +10 -0
  24. data/lib/travis/yaml/nodes/env.rb +36 -0
  25. data/lib/travis/yaml/nodes/fixed_value.rb +60 -0
  26. data/lib/travis/yaml/nodes/git.rb +9 -0
  27. data/lib/travis/yaml/nodes/jdk.rb +11 -0
  28. data/lib/travis/yaml/nodes/language.rb +18 -0
  29. data/lib/travis/yaml/nodes/language_specific.rb +45 -0
  30. data/lib/travis/yaml/nodes/mapping.rb +204 -0
  31. data/lib/travis/yaml/nodes/matrix.rb +36 -0
  32. data/lib/travis/yaml/nodes/node.rb +102 -0
  33. data/lib/travis/yaml/nodes/notifications.rb +77 -0
  34. data/lib/travis/yaml/nodes/open_mapping.rb +18 -0
  35. data/lib/travis/yaml/nodes/os.rb +21 -0
  36. data/lib/travis/yaml/nodes/os_entry.rb +19 -0
  37. data/lib/travis/yaml/nodes/root.rb +44 -0
  38. data/lib/travis/yaml/nodes/ruby.rb +11 -0
  39. data/lib/travis/yaml/nodes/scalar.rb +97 -0
  40. data/lib/travis/yaml/nodes/sequence.rb +84 -0
  41. data/lib/travis/yaml/nodes/stage.rb +6 -0
  42. data/lib/travis/yaml/nodes/version.rb +6 -0
  43. data/lib/travis/yaml/nodes/version_list.rb +7 -0
  44. data/lib/travis/yaml/nodes/virtual_env.rb +7 -0
  45. data/lib/travis/yaml/parser.rb +31 -0
  46. data/lib/travis/yaml/parser/dummy.rb +13 -0
  47. data/lib/travis/yaml/parser/psych.rb +217 -0
  48. data/lib/travis/yaml/parser/ruby.rb +77 -0
  49. data/lib/travis/yaml/secure_string.rb +12 -0
  50. data/lib/travis/yaml/version.rb +5 -0
  51. data/play/lint.rb +8 -0
  52. data/play/spec.rb +183 -0
  53. data/play/weblint.rb +296 -0
  54. data/spec/nodes/.rb +0 -0
  55. data/spec/nodes/branches_spec.rb +45 -0
  56. data/spec/nodes/bundler_args_spec.rb +9 -0
  57. data/spec/nodes/cache_spec.rb +55 -0
  58. data/spec/nodes/compiler_spec.rb +14 -0
  59. data/spec/nodes/deploy_spec.rb +83 -0
  60. data/spec/nodes/git_spec.rb +55 -0
  61. data/spec/nodes/jdk_spec.rb +41 -0
  62. data/spec/nodes/language_spec.rb +79 -0
  63. data/spec/nodes/notifications_spec.rb +45 -0
  64. data/spec/nodes/os_spec.rb +28 -0
  65. data/spec/nodes/ruby_spec.rb +69 -0
  66. data/spec/nodes/stage_spec.rb +34 -0
  67. data/spec/nodes/virtual_env_spec.rb +9 -0
  68. data/spec/parser/dummy_spec.rb +7 -0
  69. data/spec/parser/ruby_spec.rb +41 -0
  70. data/spec/support.rb +3 -0
  71. data/spec/support/coverage.rb +11 -0
  72. data/spec/support/environment.rb +1 -0
  73. data/spec/yaml_spec.rb +26 -0
  74. data/travis-yaml.gemspec +24 -0
  75. metadata +207 -0
@@ -0,0 +1,54 @@
1
+ require 'bundler/setup'
2
+ require 'benchmark'
3
+ require 'psych'
4
+ require 'safe_yaml/load'
5
+ require 'travis/yaml'
6
+
7
+ parsers = [Psych, SafeYAML, Travis::Yaml]
8
+ content = <<-YAML
9
+ # from rails/rails
10
+ script: 'ci/travis.rb'
11
+ before_install:
12
+ - travis_retry gem install bundler
13
+ - "rvm current | grep 'jruby' && export AR_JDBC=true || echo"
14
+ rvm:
15
+ - 1.9.3
16
+ - 2.0.0
17
+ - 2.1.1
18
+ - rbx-2
19
+ - jruby
20
+ env:
21
+ - "GEM=railties"
22
+ - "GEM=ap,am,amo,as,av"
23
+ - "GEM=ar:mysql"
24
+ - "GEM=ar:mysql2"
25
+ - "GEM=ar:sqlite3"
26
+ - "GEM=ar:postgresql"
27
+ matrix:
28
+ allow_failures:
29
+ - rvm: rbx-2
30
+ - rvm: jruby
31
+ fast_finish: true
32
+ notifications:
33
+ email: false
34
+ irc:
35
+ on_success: change
36
+ on_failure: always
37
+ channels:
38
+ - "irc.freenode.org#rails-contrib"
39
+ campfire:
40
+ on_success: change
41
+ on_failure: always
42
+ bundler_args: --path vendor/bundle --without test
43
+ services:
44
+ - memcached
45
+ YAML
46
+
47
+ GC.disable
48
+ Benchmark.bmbm do |x|
49
+ parsers.each do |parser|
50
+ x.report(parser.inspect) do
51
+ 500.times { parser.load(content) }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,2 @@
1
+ require_relative './play/weblint'
2
+ run Sinatra::Application
@@ -0,0 +1,43 @@
1
+ module Travis
2
+ module Yaml
3
+ Error ||= Class.new(StandardError)
4
+ ParseError ||= Class.new(Error)
5
+
6
+ require 'travis/yaml/secure_string'
7
+ require 'travis/yaml/nodes'
8
+ require 'travis/yaml/matrix'
9
+ require 'travis/yaml/parser'
10
+
11
+ extend self
12
+
13
+ def parse(value)
14
+ Parser.parse(value)
15
+ end
16
+
17
+ alias_method :load, :parse
18
+
19
+ def parse!(value, file_name = '.travis.yml')
20
+ result = parse(value)
21
+ result.nested_warnings.each do |key, message|
22
+ warn key.empty? ? "#{file_name}: #{message}" :
23
+ "#{file_name}: #{key.join(?.)} section - #{message}"
24
+ end
25
+ result
26
+ end
27
+
28
+ def new
29
+ root = Nodes::Root.new
30
+ yield root if block_given?
31
+ root.deep_verify
32
+ root
33
+ end
34
+
35
+ def matrix(value)
36
+ Matrix.new parse(value)
37
+ end
38
+
39
+ def matrix!(value, file_name = '.travis.yml')
40
+ Matrix.new parse!(value, file_name)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,65 @@
1
+ require 'delegate'
2
+
3
+ module Travis::Yaml
4
+ class Matrix < DelegateClass(Array)
5
+ EXPAND_KEYS = [
6
+ :compiler, :gemfile, :ghc, :go, :jdk, :lein, :node_js, :otp_release,
7
+ :perl, :php, :python, :ruby, :scala, :xcode_scheme, :xcode_sdk, :os
8
+ ]
9
+
10
+ KEYS = EXPAND_KEYS + [:env]
11
+
12
+ class Entry < DelegateClass(Nodes::Root)
13
+ attr_reader :env, :matrix_attributes
14
+
15
+ def initialize(root, matrix_attributes)
16
+ super(root)
17
+
18
+ @matrix_attributes = matrix_attributes
19
+ @env = Nodes::Env.new(self)
20
+ inherited_env = root.env.global if root.env
21
+ @env.global = [matrix_attributes[:env], *inherited_env].compact
22
+ end
23
+
24
+ EXPAND_KEYS.each do |key|
25
+ define_method(key) { @matrix_attributes.fetch(key, super()) }
26
+ end
27
+
28
+ def inspect
29
+ "#<#{self.class}: #{matrix_attributes}>"
30
+ end
31
+ end
32
+
33
+ attr_reader :root
34
+
35
+ def initialize(root)
36
+ @root = root
37
+ super(entries)
38
+ end
39
+
40
+ def axes
41
+ @axes ||= KEYS.select do |key|
42
+ next true if values_for(key) and values_for(key).size > 1
43
+ root.matrix.include.any? { |i| i[key] } if root.matrix and root.matrix.include
44
+ end
45
+ end
46
+
47
+ def entries
48
+ @entries ||= begin
49
+ first, *rest = axes.map { |k| values_for(k) || [nil] }
50
+ entries = Array(first).product(*rest).map { |list| Hash[axes.zip(list)] }
51
+ if m = root.matrix
52
+ entries.delete_if { |e| m.exclude.any? { |p| p.all? { |k,v| e[k.to_sym] == v } } } if m.exclude
53
+ m.include.each { |i| entries << Hash[axes.map { |k| [k, i[k]] }] } if m.include
54
+ end
55
+ entries.map! { |attributes| Entry.new(root, attributes) }
56
+ entries.any? ? entries : [root]
57
+ end
58
+ end
59
+
60
+ def values_for(key)
61
+ return root[key] unless key == :env
62
+ root.env.matrix if root.env
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,40 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ def self.[](key)
4
+ return key if key.respond_to? :new
5
+ name = constants.detect { |c| c.downcase == key }
6
+ raise ArgumentError, "unknown node type %p" % key unless name
7
+ const_get(name)
8
+ end
9
+
10
+ require 'travis/yaml/nodes/node'
11
+ require 'travis/yaml/nodes/scalar'
12
+ require 'travis/yaml/nodes/fixed_value'
13
+ require 'travis/yaml/nodes/sequence'
14
+ require 'travis/yaml/nodes/mapping'
15
+ require 'travis/yaml/nodes/open_mapping'
16
+ require 'travis/yaml/nodes/language_specific'
17
+ require 'travis/yaml/nodes/version'
18
+ require 'travis/yaml/nodes/version_list'
19
+ require 'travis/yaml/nodes/git'
20
+ require 'travis/yaml/nodes/bundler_args'
21
+ require 'travis/yaml/nodes/stage'
22
+ require 'travis/yaml/nodes/deploy_conditions'
23
+ require 'travis/yaml/nodes/deploy_entry'
24
+ require 'travis/yaml/nodes/deploy'
25
+ require 'travis/yaml/nodes/language'
26
+ require 'travis/yaml/nodes/compiler_entry'
27
+ require 'travis/yaml/nodes/compiler'
28
+ require 'travis/yaml/nodes/os_entry'
29
+ require 'travis/yaml/nodes/os'
30
+ require 'travis/yaml/nodes/virtual_env'
31
+ require 'travis/yaml/nodes/ruby'
32
+ require 'travis/yaml/nodes/jdk'
33
+ require 'travis/yaml/nodes/env'
34
+ require 'travis/yaml/nodes/matrix'
35
+ require 'travis/yaml/nodes/notifications'
36
+ require 'travis/yaml/nodes/branches'
37
+ require 'travis/yaml/nodes/cache'
38
+ require 'travis/yaml/nodes/root'
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Branches < Mapping
4
+ class Matcher < Sequence
5
+ type Scalar[:str, :regexp]
6
+ end
7
+
8
+ map :only, :except, to: Matcher
9
+ auto_prefix :only
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class BundlerArgs < Scalar
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,29 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Cache < Mapping
4
+ map :apt, :bundler, to: Scalar[:bool]
5
+ map :directories, to: Sequence
6
+
7
+ def visit_scalar(visitor, type, value, implicit = true)
8
+ case type
9
+ when :bool
10
+ visit_key_value(visitor, :bundler, value)
11
+ visit_key_value(visitor, :apt, value)
12
+ when :str
13
+ key = visitor.generate_key(self, value)
14
+ self[key] = true
15
+ else
16
+ super
17
+ end
18
+ end
19
+
20
+ def visit_sequence(visitor, value)
21
+ visitor.apply_sequence(self, value)
22
+ end
23
+
24
+ def visit_child(visitor, value)
25
+ visit_scalar(visitor, :str, value)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Compiler < Sequence
4
+ type CompilerEntry
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class CompilerEntry < FixedValue
4
+ ignore_case
5
+ default :gcc
6
+ value :gcc, :clang, :"g++" => :gcc, :"clang++" => :clang
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Deploy < Sequence
4
+ type DeployEntry
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class DeployConditions < Mapping
4
+ include LanguageSpecific
5
+ map :jdk, :node, :perl, :php, :python, :ruby, :scala, :node, to: Version
6
+ map :rvm, to: :ruby
7
+ map :repo, :branch, :condition, to: Scalar[:str]
8
+ map :all_branches, :tags, to: Scalar[:bool]
9
+ prefix_scalar :branch
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class DeployEntry < OpenMapping
4
+ prefix_scalar :provider
5
+ map :provider, to: Scalar, required: true
6
+ map :edge, to: Scalar[:bool], experimental: true
7
+ map :on, to: DeployConditions
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,36 @@
1
+ require 'shellwords'
2
+
3
+ module Travis::Yaml
4
+ module Nodes
5
+ class Env < Mapping
6
+ class Variables < Scalar
7
+ cast :str, :secure
8
+
9
+ def visit_mapping(visitor, value)
10
+ self.value = ""
11
+ visitor.apply_mapping(self, value)
12
+ end
13
+
14
+ def visit_mapping(visitor, key, value)
15
+ key = visitor.generate_key(self, key)
16
+ node = Scalar.new
17
+ visitor.accept(node, value)
18
+
19
+ if node.errors?
20
+ warning "dropping %p: %s", key, value.errors.join(', ')
21
+ else
22
+ self.value << " " unless self.value.empty?
23
+ self.value << "#{key}=#{Shellwords.escape(value.value)}"
24
+ end
25
+ end
26
+ end
27
+
28
+ class List < Sequence
29
+ type Variables
30
+ end
31
+
32
+ map :global, :matrix, to: List
33
+ auto_prefix :matrix
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,60 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class FixedValue < Scalar
4
+ def self.[](*values)
5
+ Class.new(self) { value(*values) }
6
+ end
7
+
8
+ def self.default(value = nil)
9
+ value &&= value.to_s
10
+ super(value)
11
+ end
12
+
13
+ def self.ignore_case?
14
+ @ignore_case ||= false
15
+ end
16
+
17
+ def self.ignore_case
18
+ @ignore_case = true
19
+ end
20
+
21
+ def self.valid_values
22
+ @valid_values ||= superclass.respond_to?(:valid_values) ? superclass.valid_values.dup : []
23
+ end
24
+
25
+ def self.aliases
26
+ @aliases ||= superclass.respond_to?(:aliases) ? superclass.aliases.dup : {}
27
+ end
28
+
29
+ def self.map_value(value)
30
+ value = value.to_s
31
+ if ignore_case?
32
+ all_values = valid_values + aliases.keys
33
+ value = all_values.detect { |supported| supported.downcase == value.downcase }
34
+ end
35
+ value &&= aliases.fetch(value, value)
36
+ value if valid_values.include? value
37
+ end
38
+
39
+ def self.value(*list)
40
+ list.each do |value|
41
+ if value.respond_to? :each_pair
42
+ value.each_pair { |aka, proper| aliases[aka.to_s] = proper.to_s }
43
+ else
44
+ valid_values << value.to_s
45
+ end
46
+ end
47
+ end
48
+
49
+ def value=(value)
50
+ if mapped = self.class.map_value(value)
51
+ super(mapped)
52
+ elsif self.value
53
+ warning "illegal value %p, defaulting to %p", value, self.value
54
+ elsif value
55
+ error "illegal value %p", value
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Git < Mapping
4
+ map :depth, to: Scalar[:int]
5
+ map :submodules, to: Scalar[:bool]
6
+ map :strategy, to: FixedValue[:clone, :tarball]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class JDK < VersionList
4
+ def verify_language(language)
5
+ return unless language == 'ruby'
6
+ return if @parent.ruby and @parent.ruby.jruby?
7
+ error 'specified "jdk", but "ruby" does not include "jruby"'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Language < FixedValue
4
+ ignore_case
5
+ default :ruby
6
+
7
+ value :c, :cpp, :clojure, :erlang, :go, :groovy, :haskell, :java, :node_js,
8
+ :"objective-c", :ruby, :python, :perl, :php, :scala, :android
9
+ value jvm: :java, javascript: :node_js, node: :node_js, nodejs: :node_js, golang: :go,
10
+ objective_c: :"objective-c", obj_c: :"objective-c", objc: :"objective-c"
11
+ value "c++" => :cpp, "node.js" => :node_js, "obj-c" => :"objective-c"
12
+
13
+ def default_os
14
+ value == "objective-c" ? :osx : OSEntry.default
15
+ end
16
+ end
17
+ end
18
+ end