teapot 1.3.1 → 2.0.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.travis.yml +6 -0
  4. data/Gemfile +1 -1
  5. data/bin/teapot +3 -3
  6. data/lib/teapot/command/build.rb +123 -0
  7. data/lib/teapot/{metadata.rb → command/clean.rb} +19 -20
  8. data/lib/teapot/command/create.rb +112 -0
  9. data/lib/teapot/command/fetch.rb +183 -0
  10. data/lib/teapot/command/list.rb +97 -0
  11. data/lib/teapot/command/status.rb +74 -0
  12. data/lib/teapot/command/visualize.rb +70 -0
  13. data/lib/teapot/command.rb +52 -132
  14. data/lib/teapot/context.rb +27 -11
  15. data/lib/teapot/loader.rb +6 -22
  16. data/lib/teapot/target.rb +2 -2
  17. data/lib/teapot/version.rb +1 -1
  18. data/spec/teapot/command_spec.rb +20 -12
  19. data/spec/teapot/context_spec.rb +13 -16
  20. data/teapot.gemspec +6 -4
  21. metadata +35 -45
  22. data/PLANNING.md +0 -20
  23. data/lib/teapot/controller/build.rb +0 -107
  24. data/lib/teapot/controller/clean.rb +0 -35
  25. data/lib/teapot/controller/create.rb +0 -73
  26. data/lib/teapot/controller/fetch.rb +0 -173
  27. data/lib/teapot/controller/generate.rb +0 -45
  28. data/lib/teapot/controller/list.rb +0 -82
  29. data/lib/teapot/controller/visualize.rb +0 -50
  30. data/lib/teapot/controller.rb +0 -81
  31. data/lib/teapot/dependency.rb +0 -25
  32. data/lib/teapot/generator.rb +0 -138
  33. data/lib/teapot/merge.rb +0 -142
  34. data/lib/teapot/repository.rb +0 -135
  35. data/lib/teapot/substitutions.rb +0 -258
  36. data/spec/teapot/generator_spec/teapot.rb +0 -54
  37. data/spec/teapot/generator_spec/template/$NAME.txt +0 -1
  38. data/spec/teapot/generator_spec.rb +0 -46
  39. data/spec/teapot/merge_spec.rb +0 -50
  40. data/spec/teapot/metadata_spec.rb +0 -31
  41. data/spec/teapot/substitutions_spec.rb +0 -65
  42. data/spec/teapot/wait_spec/teapot.rb +0 -41
  43. data/spec/teapot/wait_spec.rb +0 -53
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2941cf53da430cdf791523506bc5d24df115506
4
- data.tar.gz: cc7092f377444bbc67dd3232137626418f58971f
3
+ metadata.gz: c6945788efc0d75eb38df802faf17617bc67116f
4
+ data.tar.gz: bf5dd81a7bc4cf1bef005d5e584f5fbb54ba9fdd
5
5
  SHA512:
6
- metadata.gz: d3c0fabbb37b1d116467422a3309370a30e04c429dd8ca2c3b297096ae58b4143a5842c59290cd7a214bad74e244225239db32167b3788ebe9c4c588aba7dcf2
7
- data.tar.gz: 0a967401cf2bc91f38c71b2a3bb1c622f155bbe91f1e18b4a43373af8c5e5f3537ba6da6f00226dfc7f1ddfdb3ef95401eb0f02f997ea0ec7e71ba56ba5522aa
6
+ metadata.gz: 034e5b25acb19d9b75589c347d5f281147bed403ab73cc750640ad79c5fb8f3d267d273b6d96d024dcbdd0ba4a31447aaf80734d5a2bb8d383d288120bac0c6c
7
+ data.tar.gz: 9da112ffe2f501735ec6590ad2ddbce6afbab287b5ff058ac46a8b51517de237cb94e3644a047780cd90e7ec4bfed4a5a11397e848d90eecd87e951c60e25de3
data/.rspec CHANGED
@@ -1,4 +1,3 @@
1
- --color
2
1
  --format documentation
3
2
  --backtrace
4
3
  --warnings
data/.travis.yml CHANGED
@@ -14,6 +14,12 @@ rvm:
14
14
  - jruby-head
15
15
  - ruby-head
16
16
  matrix:
17
+ global:
18
+ env: CC=clang-4.0 CXX=clang++-4.0
17
19
  allow_failures:
18
20
  - rvm: ruby-head
19
21
  - rvm: jruby-head
22
+ addons:
23
+ apt:
24
+ sources: ["llvm-toolchain-trusty-4.0"]
25
+ packages: ["clang-4.0"]
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ gemspec
6
6
  group :development do
7
7
  gem 'pry'
8
8
  gem 'pry-coolline'
9
- gem 'pry-byebug'
9
+ gem 'pry-byebug', platform: :mri
10
10
  end
11
11
 
12
12
  group :test do
data/bin/teapot CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  require 'teapot/command'
24
24
 
25
- options = Teapot::Command::Top.parse(ARGV)
25
+ options = Teapot::Command.parse(ARGV)
26
26
 
27
27
  begin
28
28
  options.invoke
@@ -31,10 +31,10 @@ rescue Teapot::IncompatibleTeapotError => error
31
31
  $stderr.puts "Supported minimum version #{Teapot::MINIMUM_LOADER_VERSION.dump} to #{Teapot::LOADER_VERSION.dump}."
32
32
 
33
33
  exit 1
34
- rescue Teapot::Dependency::UnresolvedDependencyError => error
34
+ rescue Build::Dependency::UnresolvedDependencyError => error
35
35
  $stderr.puts "Unresolved dependencies:"
36
36
 
37
- error.chain.unresolved.each do |(name, parent)|
37
+ error.chain.unresolved.each do |name, parent|
38
38
  $stderr.puts "#{parent} depends on #{name.inspect}".color(:red)
39
39
 
40
40
  conflicts = error.chain.conflicts[name]
@@ -0,0 +1,123 @@
1
+ # Copyright, 2017, 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 'samovar'
22
+
23
+ require 'build/controller'
24
+
25
+ module Teapot
26
+ module Command
27
+ class BuildFailedError < StandardError
28
+ end
29
+
30
+ class Build < Samovar::Command
31
+ self.description = "Build the specified target."
32
+
33
+ options do
34
+ option '-j/-l/--limit <n>', "Limit the build to <n> concurrent processes."
35
+ option '--only', "Only build direct dependencies."
36
+ option '-c/--continuous', "Run the build graph continually (experimental)."
37
+ end
38
+
39
+ many :targets, "Build these targets, or use them to help the dependency resolution process."
40
+ split :argv, "Arguments passed to child process(es) of build if any."
41
+
42
+ def invoke(parent)
43
+ context = parent.context
44
+
45
+ chain = context.dependency_chain(@targets, context.configuration)
46
+
47
+ ordered = chain.ordered
48
+
49
+ if @options[:only]
50
+ ordered = context.direct_targets(ordered)
51
+ end
52
+
53
+ controller = ::Build::Controller.new(logger: parent.logger, limit: @options[:limit]) do |controller|
54
+ ordered.each do |resolution|
55
+ target = resolution.provider
56
+
57
+ if target.build
58
+ environment = target.environment(context.configuration, chain)
59
+
60
+ controller.add_target(target, environment.flatten, @argv)
61
+ end
62
+ end
63
+ end
64
+
65
+ walker = nil
66
+
67
+ # We need to catch interrupt here, and exit with the correct exit code:
68
+ begin
69
+ controller.run do |walker|
70
+ # show_dependencies(walker)
71
+
72
+ # Only run once is asked:
73
+ unless @options[:continuous]
74
+ if walker.failed?
75
+ raise BuildFailedError.new("Failed to build all nodes successfully!")
76
+ end
77
+
78
+ break
79
+ end
80
+ end
81
+ rescue Interrupt
82
+ if walker && walker.failed?
83
+ raise BuildFailedError.new("Failed to build all nodes successfully!")
84
+ end
85
+ end
86
+
87
+ return chain, ordered
88
+ end
89
+
90
+ def show_dependencies(walker)
91
+ outputs = {}
92
+
93
+ walker.tasks.each do |node, task|
94
+ # puts "Task #{task} (#{node}) outputs:"
95
+
96
+ task.outputs.each do |path|
97
+ path = path.to_s
98
+
99
+ # puts "\t#{path}"
100
+
101
+ outputs[path] = task
102
+ end
103
+ end
104
+
105
+ walker.tasks.each do |node, task|
106
+ dependencies = {}
107
+ task.inputs.each do |path|
108
+ path = path.to_s
109
+
110
+ if generating_task = outputs[path]
111
+ dependencies[path] = generating_task
112
+ end
113
+ end
114
+
115
+ puts "Task #{task.inspect} has #{dependencies.count} dependencies."
116
+ dependencies.each do |path, task|
117
+ puts "\t#{task.inspect}: #{path}"
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,15 +1,15 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
@@ -18,25 +18,24 @@
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 'samovar'
22
+
21
23
  module Teapot
22
- # This is a very basic class for accessing metadata from a repository. In the future I expect this will be fleshed out a bit more.
23
- class Metadata
24
- class Section
25
- def initialize(name)
26
- @name = name
27
- end
24
+ module Command
25
+ class Clean < Samovar::Command
26
+ self.description = "Delete everything in the teapot directory."
27
+
28
+ def invoke(parent)
29
+ context = parent.context
30
+ logger = parent.logger
31
+ configuration = context.configuration
32
+
33
+ logger.info "Removing #{configuration.platforms_path}...".color(:cyan)
34
+ FileUtils.rm_rf configuration.platforms_path
28
35
 
29
- def method_missing(parameter_name)
30
- `git config #{@name}.#{parameter_name}`.chomp!
36
+ logger.info "Removing #{configuration.packages_path}...".color(:cyan)
37
+ FileUtils.rm_rf configuration.packages_path
31
38
  end
32
39
  end
33
-
34
- def initialize(context)
35
- @context = context
36
- end
37
-
38
- def method_missing(name)
39
- Section.new(name)
40
- end
41
40
  end
42
41
  end
@@ -0,0 +1,112 @@
1
+ # Copyright, 2016, 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 'samovar'
22
+ require 'build/name'
23
+
24
+ require_relative 'fetch'
25
+ require 'rugged'
26
+
27
+ module Teapot
28
+ module Command
29
+ class Create < Samovar::Command
30
+ self.description = "Create a new teapot package using the specified repository."
31
+
32
+ options do
33
+ option "-t/--target-name <name>", "The target to use to create the project", default: 'Generate/Project/Initial'
34
+ end
35
+
36
+ one :project_name, "The name of the new project in title-case, e.g. 'My Project'."
37
+ one :source, "The source repository to use for fetching packages, e.g. https://github.com/kurocha."
38
+ many :packages, "Any additional packages you'd like to include in the project."
39
+
40
+ def target_name
41
+ @options[:target_name]
42
+ end
43
+
44
+ def invoke(parent)
45
+ logger = parent.logger
46
+
47
+ nested = parent['--root', parent.options[:root] || project_name.gsub(/\s+/, '-').downcase]
48
+ root = nested.root
49
+
50
+ if root.exist?
51
+ raise ArgumentError.new("#{root} already exists!")
52
+ end
53
+
54
+ # Create and set the project root:
55
+ root.create
56
+
57
+ repository = Rugged::Repository.init_at(root.to_s)
58
+
59
+ logger.info "Creating project named #{project_name} at path #{root}...".color(:cyan)
60
+ generate_project(root, @project_name, @source, @packages)
61
+
62
+ # Fetch the initial packages:
63
+ Fetch[].invoke(nested)
64
+
65
+ context = nested.context
66
+
67
+ Build[target_name, *@packages, '--', project_name].invoke(nested)
68
+
69
+ # Fetch any additional packages:
70
+ Fetch[].invoke(nested)
71
+
72
+ index = repository.index
73
+ index.add_all
74
+
75
+ Rugged::Commit.create(repository,
76
+ tree: index.write_tree(repository),
77
+ message: "Initial project files.",
78
+ parents: repository.empty? ? [] : [repository.head.target].compact,
79
+ update_ref: 'HEAD'
80
+ )
81
+ end
82
+
83
+ def generate_project(root, project_name, source, packages)
84
+ name = ::Build::Name.new(project_name)
85
+
86
+ File.open(root + ".gitignore", "w") do |output|
87
+ output.puts "teapot/"
88
+ end
89
+
90
+ File.open(root + TEAPOT_FILE, "w") do |output|
91
+ output.puts "\# Teapot v#{VERSION} configuration generated at #{Time.now.to_s}", ''
92
+
93
+ output.puts "required_version #{LOADER_VERSION.dump}", ''
94
+
95
+ output.puts "\# Build Targets", ''
96
+
97
+ output.puts "\# Configurations", ''
98
+
99
+ output.puts "define_configuration #{name.target.dump} do |configuration|"
100
+
101
+ output.puts "\tconfiguration[:source] = #{source.dump}", ''
102
+
103
+ packages.each do |name|
104
+ output.puts "\tconfiguration.require #{name.dump}"
105
+ end
106
+
107
+ output.puts "end", ''
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,183 @@
1
+ # Copyright, 2016, 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 'samovar'
22
+ require 'rugged'
23
+
24
+ module Teapot
25
+ module Command
26
+ class Fetch < Samovar::Command
27
+ self.description = "Fetch remote packages according to the specified configuration."
28
+
29
+ # 3 typical use cases:
30
+ # - fetch current packages according to lockfile
31
+ # - write current pacakges into lockfile
32
+ # - update packages and update lockfile
33
+
34
+ options do
35
+ option '--update', "Update dependencies to the latest versions."
36
+ option '--local', "Don't update from source, assume updated local packages."
37
+ end
38
+
39
+ def invoke(parent)
40
+ logger = parent.logger
41
+ context = parent.context
42
+
43
+ resolved = Set.new
44
+ configuration = context.configuration
45
+ unresolved = context.unresolved(configuration.packages)
46
+
47
+ while true
48
+ configuration.packages.each do |package|
49
+ next if resolved.include? package
50
+
51
+ fetch_package(context, configuration, package, logger, **@options)
52
+
53
+ # We are done with this package, don't try to process it again:
54
+ resolved << package
55
+ end
56
+
57
+ # Resolve any/all imports:
58
+ configuration.materialize
59
+
60
+ previously_unresolved = unresolved
61
+ unresolved = context.unresolved(configuration.packages)
62
+
63
+ # No additional packages were resolved, we have reached a fixed point:
64
+ if previously_unresolved == unresolved || unresolved.count == 0
65
+ break
66
+ end
67
+ end
68
+
69
+ if unresolved.count > 0
70
+ logger.error "Could not fetch all packages!".color(:red)
71
+ unresolved.each do |package|
72
+ logger.error "\t#{package}".color(:red)
73
+ end
74
+ else
75
+ logger.info "Completed fetch successfully.".color(:green)
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def current_metadata(package)
82
+ repository = Rugged::Repository.new(package.path.to_s)
83
+
84
+ return {
85
+ commit: repository.head.target.oid,
86
+ branch: repository.head.name.sub(/^refs\/heads\//, '')
87
+ }
88
+ end
89
+
90
+ def link_local_package(context, configuration, package, logger)
91
+ logger.info "Linking local #{package}...".color(:cyan)
92
+
93
+ local_path = context.root + package.options[:local]
94
+
95
+ # Where we are going to put the package:
96
+ destination_path = package.path
97
+
98
+ # Make the top level directory if required:
99
+ destination_path.dirname.create
100
+
101
+ unless destination_path.exist?
102
+ destination_path.make_symlink(local_path)
103
+ end
104
+ end
105
+
106
+ def clone_or_pull_package(context, configuration, package, package_lock, logger)
107
+ logger.info "Fetching #{package}...".color(:cyan)
108
+
109
+ # Where we are going to put the package:
110
+ destination_path = package.path
111
+
112
+ base_uri = URI(package.options[:source].to_s)
113
+
114
+ if base_uri.scheme == nil || base_uri.scheme == 'file'
115
+ base_uri = URI "file://" + File.expand_path(base_uri.path, context.root) + "/"
116
+ end
117
+
118
+ branch = package.options.fetch(:branch, 'master')
119
+
120
+ if package_lock
121
+ logger.info "Package locked to commit: #{package_lock[:branch]}/#{package_lock[:commit]}"
122
+
123
+ branch = package_lock[:branch]
124
+ end
125
+
126
+ commit = package_lock ? package_lock[:commit] : nil
127
+
128
+ unless destination_path.exist?
129
+ logger.info "Cloning package at path #{destination_path} ...".color(:cyan)
130
+
131
+ begin
132
+ external_url = package.external_url(context.root)
133
+
134
+ repository = Rugged::Repository.clone_at(external_url.to_s, destination_path.to_s, checkout_branch: branch)
135
+ repository.checkout(commit) if commit
136
+ # Repository.new().clone!(external_url, branch, commit)
137
+ rescue
138
+ logger.info "Failed to clone #{external_url}...".color(:red)
139
+
140
+ raise
141
+ end
142
+ else
143
+ logger.info "Updating package at path #{destination_path} ...".color(:cyan)
144
+
145
+ commit = package_lock ? package_lock[:commit] : nil
146
+ Rugged::Repository.new(destination_path.to_s).checkout(commit)
147
+ # Repository.new(destination_path).update(branch, commit)
148
+ end
149
+ end
150
+
151
+ def fetch_package(context, configuration, package, logger, update: false, local: false)
152
+ if package.local?
153
+ link_local_package(context, configuration, package, logger)
154
+ elsif package.external?
155
+ lock_store = configuration.lock_store
156
+
157
+ # If we are updating, don't bother reading the current branch/commit details.
158
+ unless update
159
+ package_lock = lock_store.transaction(true){|store| store[package.name]}
160
+ end
161
+
162
+ unless local
163
+ clone_or_pull_package(context, configuration, package, package_lock, logger)
164
+ end
165
+
166
+ # Lock the package, unless it was already locked:
167
+ unless package_lock
168
+ metadata = current_metadata(package)
169
+
170
+ lock_store.transaction do |store|
171
+ store_metadata = store[package.name]
172
+
173
+ if store_metadata.nil? or store_metadata[:commit] != metadata[:commit]
174
+ logger.info "Updating lockfile for package #{package.name}: #{metadata[:commit]}..."
175
+ store[package.name] = metadata
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,97 @@
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 'samovar'
22
+
23
+ module Teapot
24
+ module Command
25
+ class List < Samovar::Command
26
+ self.description = "List provisions and dependencies of the specified package."
27
+
28
+ many :packages, "Limit the listing to only these packages, or all packages if none specified."
29
+
30
+ def only
31
+ if @packages.any?
32
+ Set.new(@packages)
33
+ end
34
+ end
35
+
36
+ def invoke(parent)
37
+ context = parent.context
38
+ logger = parent.logger
39
+
40
+ # Should this somehow consider context.root_package?
41
+ context.configuration.packages.each do |package|
42
+ # The root package is the local package for this context:
43
+ next unless only == nil or only.include?(package.name)
44
+
45
+ logger.info "Package #{package.name} (from #{package.path}):".bright
46
+
47
+ begin
48
+ definitions = context.load(package)
49
+
50
+ definitions.each do |definition|
51
+ logger.info "\t#{definition}"
52
+
53
+ definition.description.each_line do |line|
54
+ logger.info "\t\t#{line.chomp}".color(:cyan)
55
+ end if definition.description
56
+
57
+ case definition
58
+ when Project
59
+ logger.info "\t\t- Summary: #{definition.summary}" if definition.summary
60
+ logger.info "\t\t- License: #{definition.license}" if definition.license
61
+ logger.info "\t\t- Website: #{definition.website}" if definition.website
62
+ logger.info "\t\t- Version: #{definition.version}" if definition.version
63
+
64
+ definition.authors.each do |author|
65
+ contact_text = [author.email, author.website].compact.collect{|text|" <#{text}>"}.join
66
+ logger.info "\t\t- Author: #{author.name}" + contact_text
67
+ end
68
+ when Target
69
+ definition.dependencies.each do |dependency|
70
+ logger.info "\t\t- #{dependency}".color(:red)
71
+ end
72
+
73
+ definition.provisions.each do |name, provision|
74
+ logger.info "\t\t- #{provision}".color(:green)
75
+ end
76
+ when Configuration
77
+ definition.materialize
78
+
79
+ definition.packages.each do |package|
80
+ logger.info "\t\t- #{package}".color(:green)
81
+ end
82
+
83
+ definition.imports.select(&:explicit).each do |import|
84
+ logger.info "\t\t- unmaterialised import #{import.name}".color(:red)
85
+ end
86
+ end
87
+ end
88
+ rescue NonexistantTeapotError => error
89
+ logger.info "\t#{error.message}".color(:red)
90
+ rescue IncompatibleTeapotError => error
91
+ logger.info "\t#{error.message}".color(:red)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end