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.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.travis.yml +6 -0
- data/Gemfile +1 -1
- data/bin/teapot +3 -3
- data/lib/teapot/command/build.rb +123 -0
- data/lib/teapot/{metadata.rb → command/clean.rb} +19 -20
- data/lib/teapot/command/create.rb +112 -0
- data/lib/teapot/command/fetch.rb +183 -0
- data/lib/teapot/command/list.rb +97 -0
- data/lib/teapot/command/status.rb +74 -0
- data/lib/teapot/command/visualize.rb +70 -0
- data/lib/teapot/command.rb +52 -132
- data/lib/teapot/context.rb +27 -11
- data/lib/teapot/loader.rb +6 -22
- data/lib/teapot/target.rb +2 -2
- data/lib/teapot/version.rb +1 -1
- data/spec/teapot/command_spec.rb +20 -12
- data/spec/teapot/context_spec.rb +13 -16
- data/teapot.gemspec +6 -4
- metadata +35 -45
- data/PLANNING.md +0 -20
- data/lib/teapot/controller/build.rb +0 -107
- data/lib/teapot/controller/clean.rb +0 -35
- data/lib/teapot/controller/create.rb +0 -73
- data/lib/teapot/controller/fetch.rb +0 -173
- data/lib/teapot/controller/generate.rb +0 -45
- data/lib/teapot/controller/list.rb +0 -82
- data/lib/teapot/controller/visualize.rb +0 -50
- data/lib/teapot/controller.rb +0 -81
- data/lib/teapot/dependency.rb +0 -25
- data/lib/teapot/generator.rb +0 -138
- data/lib/teapot/merge.rb +0 -142
- data/lib/teapot/repository.rb +0 -135
- data/lib/teapot/substitutions.rb +0 -258
- data/spec/teapot/generator_spec/teapot.rb +0 -54
- data/spec/teapot/generator_spec/template/$NAME.txt +0 -1
- data/spec/teapot/generator_spec.rb +0 -46
- data/spec/teapot/merge_spec.rb +0 -50
- data/spec/teapot/metadata_spec.rb +0 -31
- data/spec/teapot/substitutions_spec.rb +0 -65
- data/spec/teapot/wait_spec/teapot.rb +0 -41
- data/spec/teapot/wait_spec.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6945788efc0d75eb38df802faf17617bc67116f
|
4
|
+
data.tar.gz: bf5dd81a7bc4cf1bef005d5e584f5fbb54ba9fdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 034e5b25acb19d9b75589c347d5f281147bed403ab73cc750640ad79c5fb8f3d267d273b6d96d024dcbdd0ba4a31447aaf80734d5a2bb8d383d288120bac0c6c
|
7
|
+
data.tar.gz: 9da112ffe2f501735ec6590ad2ddbce6afbab287b5ff058ac46a8b51517de237cb94e3644a047780cd90e7ec4bfed4a5a11397e848d90eecd87e951c60e25de3
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/bin/teapot
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'teapot/command'
|
24
24
|
|
25
|
-
options = Teapot::Command
|
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
|
34
|
+
rescue Build::Dependency::UnresolvedDependencyError => error
|
35
35
|
$stderr.puts "Unresolved dependencies:"
|
36
36
|
|
37
|
-
error.chain.unresolved.each do |
|
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,
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
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
|