teapot 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4f0ac3f8f5a835ed05d72ed5789a28617dc89672
4
- data.tar.gz: 9cdbc779f23d8f16787091936845897a8ebfcaca
5
- SHA512:
6
- metadata.gz: 763f58203bf5632541edf4cb1db726b955e7971adda43d7af17c0a816ac5dcbd8a0b5d52464c0564824c2e2550ebef04c785ac641f38bb4eb09156f3efb528d1
7
- data.tar.gz: 2aa81a03e51e0d1cd0a4e028cfc610590941d4522de5b6ae549c80146719d141f3508e3afc3067c82e234f0dd95831b5292295fef42e1bcf89281566e26307d4
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTIzOGRjMDQzOGJmOTZmZmE0ODQ0NWU4MzA2YTNiMTJhYWU0YWI4Yg==
5
+ data.tar.gz: !binary |-
6
+ NTc4YWMzMjdjNjE4M2I0MWUxMmQxYjBhN2NlMmZiMTgwY2NkYThkNQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTMxYzQ2Mzg3ODAzOTNiYjBhMDkzOTllOGM1NGE3YjUyNDczMzhkNGNlZWIz
10
+ MDJhMzUyMDlmNWFhOGM1YzQ3YzBjMDNmNDlhYzVkYjdlNjliOWQ4MzFlZTM5
11
+ MDY0M2UwMmQzNDI5MmNkOWE0MWZiMjhlNTJiZTE3MTE3ZTkyMjE=
12
+ data.tar.gz: !binary |-
13
+ OTIxOTIzNWVmZWVhZjMxZDU3OWZlYjk3NzZmOTgwNWE4YzkyYzUyOGNjMGNi
14
+ ZDIxNWFkYTAwYzQ1ZWZlYzdmY2I2MzU2M2RlMGU4ZDM2OGRhNmNkMWNjM2Rm
15
+ ODlkYzFiOWJhYjE4ZTEwOTliYTQwOTRhNjE3NDRlMzY0NjI5Mzg=
@@ -25,6 +25,16 @@ require 'facter'
25
25
 
26
26
  module Teapot
27
27
  module Commands
28
+ module Helpers
29
+ def run_executable(path, environment)
30
+ environment = environment.flatten
31
+
32
+ executable = environment[:install_prefix] + path
33
+
34
+ Commands.run(executable)
35
+ end
36
+ end
37
+
28
38
  def self.processor_count
29
39
  # Get the number of virtual/physical processors
30
40
  count = Facter.processorcount.to_i rescue 1
@@ -43,6 +53,9 @@ module Teapot
43
53
  def self.run(*args)
44
54
  args = args.flatten.collect &:to_s
45
55
 
56
+ # Ensure we aren't invoking the shell
57
+ args[0] = [args[0], args[0]]
58
+
46
59
  puts args.join(' ').color(:blue)
47
60
 
48
61
  if system(*args)
@@ -45,6 +45,7 @@ module Teapot
45
45
  @targets = {}
46
46
  @generators = {}
47
47
  @configurations = {}
48
+ @projects = {}
48
49
 
49
50
  @dependencies = []
50
51
  @selection = Set.new
@@ -72,6 +73,7 @@ module Teapot
72
73
 
73
74
  attr :targets
74
75
  attr :generators
76
+ attr :projects
75
77
 
76
78
  # All public configurations.
77
79
  attr :configurations
@@ -79,6 +81,9 @@ module Teapot
79
81
  # The context's primary configuration.
80
82
  attr :configuration
81
83
 
84
+ # The context's primary project.
85
+ attr :project
86
+
82
87
  attr :dependencies
83
88
  attr :selection
84
89
 
@@ -128,6 +133,12 @@ module Teapot
128
133
 
129
134
  @configurations[definition.name] = definition
130
135
  end
136
+ when Project
137
+ AlreadyDefinedError.check(definition, @projects)
138
+
139
+ @project ||= definition
140
+
141
+ @projects[definition.name] = definition
131
142
  end
132
143
  end
133
144
 
@@ -38,6 +38,16 @@ module Teapot
38
38
  end if definition.description
39
39
 
40
40
  case definition
41
+ when Project
42
+ log "\t\t- Summary: #{definition.summary}" if definition.summary
43
+ log "\t\t- License: #{definition.license}" if definition.license
44
+ log "\t\t- Website: #{definition.website}" if definition.website
45
+ log "\t\t- Version: #{definition.version}" if definition.version
46
+
47
+ definition.authors.each do |author|
48
+ contact_text = [author.email, author.website].compact.collect{|text|" <#{text}>"}.join
49
+ log "\t\t- Author: #{author.name}" + contact_text
50
+ end
41
51
  when Target
42
52
  definition.dependencies.each do |name|
43
53
  log "\t\t- depends on #{name.inspect}".color(:red)
@@ -1,15 +1,15 @@
1
1
  # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
5
5
  # in the Software without restriction, including without limitation the rights
6
6
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
7
  # copies of the Software, and to permit persons to whom the Software is
8
8
  # furnished to do so, subject to the following conditions:
9
- #
9
+ #
10
10
  # The above copyright notice and this permission notice shall be included in
11
11
  # all copies or substantial portions of the Software.
12
- #
12
+ #
13
13
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
14
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
15
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -20,14 +20,18 @@
20
20
 
21
21
  require 'teapot/definition'
22
22
  require 'teapot/substitutions'
23
+ require 'teapot/merge'
23
24
 
24
25
  require 'tempfile'
25
26
 
26
27
  module Teapot
28
+ class GeneratorError < StandardError
29
+ end
30
+
27
31
  class Generator < Definition
28
32
  def initialize(context, package, name)
29
33
  super context, package, name
30
-
34
+
31
35
  @generate = nil
32
36
  end
33
37
 
@@ -38,56 +42,52 @@ module Teapot
38
42
  def generate!(*args)
39
43
  @generate[*args]
40
44
  end
41
-
45
+
42
46
  def substitute(text, substitutions)
43
47
  return text unless substitutions
44
-
48
+
45
49
  if Hash === substitutions
46
50
  pattern = Regexp.new(substitutions.keys.map{|x| Regexp.escape(x)}.join('|'))
47
-
51
+
48
52
  text.gsub(pattern) {|key| substitutions[key]}
49
53
  else
50
54
  substitutions.call(text)
51
55
  end
52
56
  end
53
-
57
+
54
58
  def write(source, destination, substitutions = nil, mode = "a")
55
59
  source_path = Pathname(path) + source
56
60
  destination_path = Pathname(context.root) + destination
57
-
61
+
58
62
  destination_path.dirname.mkpath
59
-
63
+
60
64
  File.open(destination_path, mode) do |file|
61
65
  text = File.read(source_path)
62
-
66
+
63
67
  file.write substitute(text, substitutions)
64
68
  end
65
69
  end
66
-
70
+
67
71
  def append(source, destination, substitutions = nil)
68
72
  write(source, destination, substitutions, "a")
69
73
  end
70
-
74
+
71
75
  def merge(source, destination, substitutions = nil)
72
76
  source_path = Pathname(path) + source
73
77
  destination_path = Pathname(context.root) + destination
74
-
78
+
75
79
  if destination_path.exist?
76
80
  temporary_file = Tempfile.new(destination_path.basename.to_s)
77
-
81
+
78
82
  # This functionality works, but needs improvements.
79
83
  begin
80
84
  # Need to ask user what to do?
81
85
  write(source_path, temporary_file.path, substitutions, "w")
82
-
83
- if temporary_file.read != destination_path.read
84
- if `which opendiff`.chomp != ''
85
- system("opendiff", "-merge", destination_path.to_s, destination_path.to_s, temporary_file.path)
86
- elsif `which sdiff`.chomp != ''
87
- system("sdiff", "-o", destination_path.to_s, destination_path.to_s, temporary_file.path)
88
- else
89
- abort "Can't find diff/merge tools. Please install sdiff!"
90
- end
86
+
87
+ result = Merge::combine(destination.readlines, temporary_file.readlines)
88
+
89
+ destination.open("w") do |file|
90
+ file.write result.join
91
91
  end
92
92
  ensure
93
93
  temporary_file.unlink
@@ -96,13 +96,13 @@ module Teapot
96
96
  write(source_path, destination_path, substitutions, "w")
97
97
  end
98
98
  end
99
-
99
+
100
100
  def copy(source, destination, substitutions = nil)
101
101
  source_path = Pathname(path) + source
102
-
102
+
103
103
  if source_path.directory?
104
104
  destination_path = Pathname(context.root) + destination
105
-
105
+
106
106
  source_path.children(false).each do |child_path|
107
107
  copy(source_path + child_path, destination_path + substitute(child_path.to_s, substitutions), substitutions)
108
108
  end
data/lib/teapot/loader.rb CHANGED
@@ -18,6 +18,7 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require 'teapot/project'
21
22
  require 'teapot/target'
22
23
  require 'teapot/generator'
23
24
  require 'teapot/configuration'
@@ -26,7 +27,7 @@ require 'teapot/name'
26
27
  require 'teapot/build'
27
28
 
28
29
  module Teapot
29
- LOADER_VERSION = "0.8"
30
+ LOADER_VERSION = "0.9"
30
31
  MINIMUM_LOADER_VERSION = "0.8"
31
32
 
32
33
  class IncompatibleTeapotError < StandardError
@@ -55,6 +56,9 @@ module Teapot
55
56
  # Provides build_directory and build_external methods
56
57
  include Build::Helpers
57
58
 
59
+ # Provides run_executable and other related methods.
60
+ include Commands::Helpers
61
+
58
62
  def initialize(context, package)
59
63
  @context = context
60
64
  @package = package
@@ -80,6 +84,14 @@ module Teapot
80
84
 
81
85
  alias required_version teapot_version
82
86
 
87
+ def define_project(*args)
88
+ project = Project.new(@context, @package, *args)
89
+
90
+ yield project
91
+
92
+ @defined << project
93
+ end
94
+
83
95
  def define_target(*args)
84
96
  target = Target.new(@context, @package, *args)
85
97
 
@@ -99,10 +111,10 @@ module Teapot
99
111
  def define_configuration(*args)
100
112
  configuration = Configuration.new(@context, @package, *args)
101
113
 
102
- yield configuration
103
-
104
114
  configuration.top!
105
115
 
116
+ yield configuration
117
+
106
118
  @defined << configuration
107
119
  end
108
120
 
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ module Teapot
23
+ module Merge
24
+ Difference = Struct.new(:type, :value)
25
+
26
+ def self.combine(old_text, new_text)
27
+ lcs = lcs(old_text, new_text)
28
+ changes = []
29
+
30
+ n = 0; o = 0; l = 0
31
+ while o < old_text.size and n < new_text.size and l < lcs.size
32
+ if !similar(old_text[o], lcs[l])
33
+ changes << Difference.new(:old, old_text[o])
34
+ o+=1
35
+ elsif !similar(new_text[n], lcs[l])
36
+ changes << Difference.new(:new, new_text[n])
37
+ n+=1
38
+ else
39
+ changes << Difference.new(:both, lcs[l])
40
+ o+=1; n+=1; l+=1
41
+ end
42
+ end
43
+
44
+ changes.map do |change|
45
+ change.value
46
+ end
47
+ end
48
+
49
+ # This code is based directly on the Text gem implementation
50
+ # Returns a value representing the "cost" of transforming str1 into str2
51
+ def self.levenshtein_distance(s, t)
52
+ n = s.length
53
+ m = t.length
54
+
55
+ return m if n == 0
56
+ return n if m == 0
57
+
58
+ d = (0..m).to_a
59
+ x = nil
60
+
61
+ n.times do |i|
62
+ e = i+1
63
+
64
+ m.times do |j|
65
+ cost = (s[i] == t[j]) ? 0 : 1
66
+ x = [
67
+ d[j+1] + 1, # insertion
68
+ e + 1, # deletion
69
+ d[j] + cost # substitution
70
+ ].min
71
+ d[j] = e
72
+ e = x
73
+ end
74
+
75
+ d[m] = x
76
+ end
77
+
78
+ return x
79
+ end
80
+
81
+ # Calculate the similarity of two sequences, return true if they are with factor% similarity.
82
+ def self.similar(s, t, factor = 0.15)
83
+ return true if s == t
84
+
85
+ distance = levenshtein_distance(s, t)
86
+ average_length = (s.length + t.length) / 2.0
87
+
88
+ proximity = (distance.to_f / average_length)
89
+
90
+ return proximity <= factor
91
+ end
92
+
93
+ LCSNode = Struct.new(:value, :previous)
94
+
95
+ # Find the Longest Common Subsequence in the given sequences x, y.
96
+ def self.lcs(x, y)
97
+ # Create the lcs matrix:
98
+ m = Array.new(x.length + 1) do
99
+ Array.new(y.length + 1) do
100
+ LCSNode.new(nil, nil)
101
+ end
102
+ end
103
+
104
+ # LCS(i, 0) and LCS(0, j) are always 0:
105
+ for i in 0..x.length do m[i][0].value = 0 end
106
+ for j in 0..y.length do m[0][j].value = 0 end
107
+
108
+ # Main algorithm, solve row by row:
109
+ for i in 1..x.length do
110
+ for j in 1..y.length do
111
+ if similar(x[i-1], y[j-1])
112
+ # Value is based on maximizing the length of the matched strings:
113
+ m[i][j].value = m[i-1][j-1].value + (x[i-1].chomp.length + y[j-1].chomp.length) / 2.0
114
+ m[i][j].previous = [-1, -1]
115
+ else
116
+ if m[i-1][j].value >= m[i][j-1].value
117
+ m[i][j].value = m[i-1][j].value
118
+ m[i][j].previous = [-1, 0]
119
+ else
120
+ m[i][j].value = m[i][j-1].value
121
+ m[i][j].previous = [0, -1]
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ # Get the solution by following the path backwards from m[x.length][y.length]
128
+ lcs = []
129
+
130
+ i = x.length; j = y.length
131
+ until m[i][j].previous == nil do
132
+ if m[i][j].previous == [-1, -1]
133
+ lcs << x[i-1]
134
+ end
135
+
136
+ i, j = i + m[i][j].previous[0], j + m[i][j].previous[1]
137
+ end
138
+
139
+ return lcs.reverse!
140
+ end
141
+ end
142
+ end
data/lib/teapot/name.rb CHANGED
@@ -34,8 +34,8 @@ module Teapot
34
34
  @target ||= @text.gsub(/\s+/, '-').downcase
35
35
  end
36
36
 
37
- def macro
38
- @guard ||= @text.upcase.gsub(/\s+/, '_')
37
+ def macro(prefix = [])
38
+ (Array(prefix) + [@text]).collect{|name| name.upcase.gsub(/\s+/, '_')}.join('_')
39
39
  end
40
40
  end
41
41
  end
@@ -0,0 +1,45 @@
1
+ # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'teapot/definition'
22
+
23
+ module Teapot
24
+ class Project < Definition
25
+ Author = Struct.new(:name, :email, :website)
26
+
27
+ def initialize(context, package, name)
28
+ super context, package, name
29
+
30
+ @version = "0.0.0"
31
+ @authors = []
32
+ end
33
+
34
+ attr :summary, true
35
+ attr :license, true
36
+ attr :website, true
37
+ attr :version, true
38
+
39
+ attr :authors
40
+
41
+ def add_author name, options
42
+ @authors << Author.new(name, options[:email], options[:website])
43
+ end
44
+ end
45
+ end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Teapot
22
- VERSION = "0.8.3"
22
+ VERSION = "0.9.0"
23
23
  end
metadata CHANGED
@@ -1,74 +1,74 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teapot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-12 00:00:00.000000000 Z
11
+ date: 2013-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ! '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ! '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rexec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ! '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ! '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: trollop
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ! '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ! '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: facter
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ! '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description: "\tTeapot is a tool for managing complex cross-platform builds. It provides\n\tadvanced
70
- dependency management via the Teapot file and is supported by\n\tthe infusions ecosystem
71
- of packages and platform tooling.\n"
69
+ description: ! "\tTeapot is a tool for managing complex cross-platform builds. It
70
+ provides\n\tadvanced dependency management via the Teapot file and is supported
71
+ by\n\tthe infusions ecosystem of packages and platform tooling.\n"
72
72
  email:
73
73
  - samuel.williams@oriontransfer.co.nz
74
74
  executables:
@@ -120,8 +120,10 @@ files:
120
120
  - lib/teapot/generator.rb
121
121
  - lib/teapot/graph.rb
122
122
  - lib/teapot/loader.rb
123
+ - lib/teapot/merge.rb
123
124
  - lib/teapot/name.rb
124
125
  - lib/teapot/package.rb
126
+ - lib/teapot/project.rb
125
127
  - lib/teapot/substitutions.rb
126
128
  - lib/teapot/target.rb
127
129
  - lib/teapot/version.rb
@@ -140,17 +142,17 @@ require_paths:
140
142
  - lib
141
143
  required_ruby_version: !ruby/object:Gem::Requirement
142
144
  requirements:
143
- - - '>='
145
+ - - ! '>='
144
146
  - !ruby/object:Gem::Version
145
147
  version: 1.9.3
146
148
  required_rubygems_version: !ruby/object:Gem::Requirement
147
149
  requirements:
148
- - - '>='
150
+ - - ! '>='
149
151
  - !ruby/object:Gem::Version
150
152
  version: '0'
151
153
  requirements: []
152
154
  rubyforge_project:
153
- rubygems_version: 2.0.3
155
+ rubygems_version: 2.0.2
154
156
  signing_key:
155
157
  specification_version: 4
156
158
  summary: Teapot is a tool for managing complex cross-platform builds.