teapot 1.3.1 → 2.0.0.pre.rc1
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 +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
|