teapot 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ # Copyright, 2012, 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/controller'
22
+
23
+ module Teapot
24
+ class Controller
25
+ def generate(name, arguments)
26
+ context, configuration = load_teapot
27
+
28
+ configuration.load_all
29
+
30
+ generator = context.generators[name]
31
+
32
+ unless generator
33
+ abort "Could not find generator with name #{name.inspect}".color(:red)
34
+ end
35
+
36
+ log "Generating #{name.inspect} with arguments #{arguments.inspect}".color(:cyan)
37
+ generator.generate!(*arguments)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,79 @@
1
+ # Copyright, 2012, 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/controller'
22
+
23
+ module Teapot
24
+ class Controller
25
+ def list
26
+ context, configuration = load_teapot
27
+
28
+ # Should this somehow consider context.root_package?
29
+ configuration.packages.each do |package|
30
+ log "Package #{package.name} (from #{package.path}):".bright
31
+
32
+ begin
33
+ definitions = context.load(package)
34
+
35
+ definitions.each do |definition|
36
+ log "\t#{definition}"
37
+
38
+ definition.description.each_line do |line|
39
+ log "\t\t#{line.chomp}".color(:cyan)
40
+ end if definition.description
41
+
42
+ case definition
43
+ when Target
44
+ definition.dependencies.each do |name|
45
+ log "\t\t- depends on #{name.inspect}".color(:red)
46
+ end
47
+
48
+ definition.provisions.each do |(name, provision)|
49
+ if Dependency::Alias === provision
50
+ log "\t\t- provides #{name.inspect} => #{provision.dependencies.inspect}".color(:green)
51
+ else
52
+ log "\t\t- provides #{name.inspect}".color(:green)
53
+ end
54
+ end
55
+ when Configuration
56
+ definition = definition.materialize
57
+
58
+ definition.packages.each do |package|
59
+ if package.local?
60
+ log "\t\t- links #{package.name} from #{package.options[:local]}".color(:green)
61
+ elsif package.external?
62
+ log "\t\t- clones #{package.name} from #{package.external_url(context.root)}".color(:green)
63
+ else
64
+ log "\t\t- references #{package.name} from #{package.path}".color(:green)
65
+ end
66
+ end
67
+
68
+ definition.imports.each do |import|
69
+ log "\t\t- unmaterialised import #{import.name}".color(:red)
70
+ end
71
+ end
72
+ end
73
+ rescue NonexistantTeapotError => error
74
+ log "\t#{error.message}".color(:red)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,61 @@
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
+ module Teapot
22
+ class Definition
23
+ def initialize(context, package, name)
24
+ @context = context
25
+ @package = package
26
+
27
+ @name = name
28
+
29
+ @description = nil
30
+ end
31
+
32
+ # The context in which the definition was loaded:
33
+ attr :context
34
+
35
+ # The package in which the definition was specified:
36
+ attr :package
37
+
38
+ # The name of the definition:
39
+ attr :name
40
+
41
+ # A textual description of the definition, possibly in markdown format:
42
+ attr :description, true
43
+
44
+ def description=(text)
45
+ if text =~ /^(\t+)/
46
+ text = text.gsub(/#{$1}/, '')
47
+ end
48
+
49
+ @description = text
50
+ end
51
+
52
+ # The path that the definition is relative to:
53
+ def path
54
+ @package.path
55
+ end
56
+
57
+ def to_s
58
+ "<#{self.class.name} #{@name.dump}>"
59
+ end
60
+ end
61
+ end
@@ -43,7 +43,7 @@ module Teapot
43
43
  else
44
44
  aliases = name_or_aliases
45
45
 
46
- aliases.each do |(name, dependencies)|
46
+ aliases.each do |name, dependencies|
47
47
  provisions[name] = Alias.new(Array dependencies)
48
48
  end
49
49
  end
@@ -0,0 +1,109 @@
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
+ require 'tempfile'
23
+
24
+ module Teapot
25
+ class Generator < Definition
26
+ def initialize(context, package, name)
27
+ super context, package, name
28
+
29
+ @generate = nil
30
+ end
31
+
32
+ def generate(&block)
33
+ @generate = Proc.new(&block)
34
+ end
35
+
36
+ def generate!(*args)
37
+ @generate[*args]
38
+ end
39
+
40
+ def substitute(text, substitutions)
41
+ return text unless substitutions
42
+
43
+ # Use positive look behind so that the pattern is just the substitution key:
44
+ pattern = Regexp.new(substitutions.keys.map{|x| Regexp.escape(x)}.join('|'))
45
+
46
+ text.gsub(pattern) {|key| substitutions[key]}
47
+ end
48
+
49
+ def write(source, destination, substitutions = nil, mode = "a")
50
+ source_path = Pathname(path) + source
51
+ destination_path = Pathname(context.root) + destination
52
+
53
+ destination_path.dirname.mkpath
54
+
55
+ File.open(destination_path, mode) do |file|
56
+ text = File.read(source_path)
57
+
58
+ file.write substitute(text, substitutions)
59
+ end
60
+ end
61
+
62
+ def append(source, destination, substitutions = nil)
63
+ write(source, destination, substitutions, "a")
64
+ end
65
+
66
+ def merge(source, destination, substitutions = nil)
67
+ source_path = Pathname(path) + source
68
+ destination_path = Pathname(context.root) + destination
69
+
70
+ if destination_path.exist?
71
+ temporary_file = Tempfile.new(destination_path.basename.to_s)
72
+
73
+ # This functionality works, but needs improvements.
74
+ begin
75
+ # Need to ask user what to do?
76
+ write(source_path, temporary_file.path, substitutions, "w")
77
+
78
+ if temporary_file.read != destination_path.read
79
+ if `which opendiff`.chomp != ''
80
+ system("opendiff", "-merge", destination_path.to_s, destination_path.to_s, temporary_file.path)
81
+ elsif `which sdiff`.chomp != ''
82
+ system("sdiff", "-o", destination_path.to_s, destination_path.to_s, temporary_file.path)
83
+ else
84
+ abort "Can't find diff/merge tools. Please install sdiff!"
85
+ end
86
+ end
87
+ ensure
88
+ temporary_file.unlink
89
+ end
90
+ else
91
+ write(source_path, destination_path, substitutions, "w")
92
+ end
93
+ end
94
+
95
+ def copy(source, destination, substitutions = nil)
96
+ source_path = Pathname(path) + source
97
+
98
+ if source_path.directory?
99
+ destination_path = Pathname(context.root) + destination
100
+
101
+ source_path.children(false).each do |child_path|
102
+ copy(source_path + child_path, destination_path + substitute(child_path.to_s, substitutions), substitutions)
103
+ end
104
+ else
105
+ merge(source_path, destination, substitutions)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,135 @@
1
+ # Copyright, 2012, 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/target'
22
+ require 'teapot/generator'
23
+ require 'teapot/configuration'
24
+
25
+ require 'teapot/name'
26
+ require 'teapot/build'
27
+
28
+ module Teapot
29
+ LOADER_VERSION = "0.7"
30
+ MINIMUM_LOADER_VERSION = "0.7"
31
+
32
+ class IncompatibleTeapotError < StandardError
33
+ def initialize(version)
34
+ super "Version #{version} isn't compatible with current loader! Minimum supported version: #{MINIMUM_LOADER_VERSION}; Current version: #{LOADER_VERSION}."
35
+ end
36
+
37
+ attr :version
38
+ end
39
+
40
+ class NonexistantTeapotError < StandardError
41
+ def initialize(path)
42
+ super "Could not load #{path}!"
43
+ end
44
+
45
+ attr :path
46
+ end
47
+
48
+ class Loader
49
+ class Definitions < Array
50
+ def default_configuration
51
+ find{|definition| Configuration === definition}
52
+ end
53
+ end
54
+
55
+ # Provides build_directory and build_external methods
56
+ include Build::Helpers
57
+
58
+ def initialize(context, package)
59
+ @context = context
60
+ @package = package
61
+
62
+ @defined = Definitions.new
63
+ @version = nil
64
+ end
65
+
66
+ attr :context
67
+ attr :package
68
+ attr :defined
69
+ attr :version
70
+
71
+ def teapot_version(version)
72
+ version = version[0..2]
73
+
74
+ if version >= MINIMUM_LOADER_VERSION && version <= LOADER_VERSION
75
+ @version = version
76
+ else
77
+ raise IncompatibleTeapotError.new(version)
78
+ end
79
+ end
80
+
81
+ alias required_version teapot_version
82
+
83
+ def define_target(*args)
84
+ target = Target.new(@context, @package, *args)
85
+
86
+ yield target
87
+
88
+ @defined << target
89
+ end
90
+
91
+ def define_generator(*args)
92
+ generator = Generator.new(@context, @package, *args)
93
+
94
+ yield generator
95
+
96
+ @defined << generator
97
+ end
98
+
99
+ def define_configuration(*args)
100
+ configuration = Configuration.new(@context, @package, *args)
101
+
102
+ yield configuration
103
+
104
+ configuration.top!
105
+
106
+ @defined << configuration
107
+ end
108
+
109
+ # Checks the host patterns and executes the block if they match.
110
+ def host(*args, &block)
111
+ name = @context.options[:host_platform] || RUBY_PLATFORM
112
+
113
+ if block_given?
114
+ if args.find{|arg| arg === name}
115
+ yield
116
+ end
117
+ else
118
+ name
119
+ end
120
+ end
121
+
122
+ # Load a teapot.rb file relative to the root of the @package.
123
+ def load(path)
124
+ absolute_path = @package.path + path
125
+
126
+ raise NonexistantTeapotError.new(absolute_path) unless File.exist?(absolute_path)
127
+
128
+ self.instance_eval(absolute_path.read, absolute_path.to_s)
129
+
130
+ if @version == nil
131
+ raise IncompatibleTeapotError.new("<unspecified>")
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,37 @@
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
+ module Teapot
22
+ class Name
23
+ def initialize(text)
24
+ @text = text
25
+ end
26
+
27
+ attr :text
28
+
29
+ def identifier
30
+ @identifier ||= @text.gsub(/\s+/, '')
31
+ end
32
+
33
+ def target
34
+ @target ||= @text.gsub(/\s+/, '-').downcase
35
+ end
36
+ end
37
+ end