skippy 0.2.0.a → 0.3.0.a
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 +5 -5
- data/.gitignore +1 -0
- data/.gitmodules +3 -0
- data/.idea/.rakeTasks +6 -6
- data/.idea/codeStyleSettings.xml +8 -8
- data/.idea/encodings.xml +5 -5
- data/.idea/inspectionProfiles/Project_Default.xml +7 -7
- data/.idea/misc.xml +3 -3
- data/.idea/modules.xml +7 -7
- data/.idea/skippy.iml +89 -82
- data/.idea/vcs.xml +5 -5
- data/.rubocop.yml +93 -0
- data/.rubocop_todo.yml +24 -0
- data/.vscode/launch.json +51 -61
- data/.vscode/settings.json +41 -2
- data/.vscode/tasks.json +16 -16
- data/Gemfile +11 -2
- data/README.md +194 -15
- data/Rakefile +1 -1
- data/app/boot.rb +1 -1
- data/app/commands/install.rb +41 -0
- data/app/commands/lib.rb +42 -2
- data/app/commands/new.rb +22 -8
- data/app/commands/template.rb +2 -2
- data/bin/rubocop +17 -0
- data/bin/ruby-parse +17 -0
- data/bin/ruby-rewrite +17 -0
- data/debug/skippy.bat +2 -0
- data/fixtures/my_lib/{src → modules}/command.rb +0 -0
- data/fixtures/my_lib/{src → modules}/geometry.rb +0 -0
- data/fixtures/my_lib/modules/gl.rb +4 -0
- data/fixtures/my_lib/modules/gl/container.rb +8 -0
- data/fixtures/my_lib/modules/gl/control.rb +6 -0
- data/fixtures/my_lib/modules/gl/nested/nested.rb +8 -0
- data/fixtures/my_lib/{src → modules}/tool.rb +0 -0
- data/fixtures/my_lib/skippy.json +1 -1
- data/fixtures/my_project/skippy.json +2 -1
- data/fixtures/my_project/src/hello_world.rb +2 -2
- data/fixtures/my_project/src/hello_world/extension.json +9 -9
- data/fixtures/project_with_lib/.skippy/libs/my-lib/modules/command.rb +4 -0
- data/fixtures/project_with_lib/.skippy/libs/my-lib/modules/gl.rb +4 -0
- data/fixtures/project_with_lib/.skippy/libs/my-lib/modules/gl/container.rb +8 -0
- data/fixtures/project_with_lib/.skippy/libs/my-lib/modules/gl/control.rb +6 -0
- data/fixtures/project_with_lib/.skippy/libs/my-lib/skippy.json +5 -0
- data/fixtures/project_with_lib/.skippy/libs/my-other-lib/modules/something.rb +4 -0
- data/fixtures/project_with_lib/.skippy/libs/my-other-lib/skippy.json +5 -0
- data/fixtures/project_with_lib/skippy.json +25 -0
- data/fixtures/project_with_lib/skippy/commands/example.rb +14 -0
- data/fixtures/project_with_lib/src/hello_world.rb +47 -0
- data/fixtures/project_with_lib/src/hello_world/extension.json +10 -0
- data/fixtures/project_with_lib/src/hello_world/main.rb +21 -0
- data/fixtures/project_with_lib/src/hello_world/vendor/my-lib/command.rb +4 -0
- data/fixtures/project_with_lib/src/hello_world/vendor/my-other-lib/something.rb +4 -0
- data/lib/skippy.rb +2 -0
- data/lib/skippy/app.rb +2 -2
- data/lib/skippy/cli.rb +41 -20
- data/lib/skippy/command.rb +2 -4
- data/lib/skippy/config.rb +27 -22
- data/lib/skippy/config_accessors.rb +12 -12
- data/lib/skippy/group.rb +1 -3
- data/lib/skippy/helpers/file.rb +3 -3
- data/lib/skippy/installer.rb +49 -0
- data/lib/skippy/installer/git.rb +115 -0
- data/lib/skippy/installer/local.rb +19 -0
- data/lib/skippy/lib_module.rb +16 -16
- data/lib/skippy/lib_source.rb +139 -0
- data/lib/skippy/library.rb +50 -10
- data/lib/skippy/library_manager.rb +116 -18
- data/lib/skippy/module_manager.rb +104 -26
- data/lib/skippy/namespace.rb +17 -1
- data/lib/skippy/project.rb +34 -4
- data/lib/skippy/version.rb +3 -1
- data/skippy.gemspec +10 -5
- metadata +85 -29
- data/cSpell.json +0 -18
data/lib/skippy/app.rb
CHANGED
@@ -40,9 +40,9 @@ class Skippy::App
|
|
40
40
|
def templates
|
41
41
|
result = []
|
42
42
|
templates_source_path.entries.each { |entry|
|
43
|
-
template_path =
|
43
|
+
template_path = templates_source_path.join(entry)
|
44
44
|
next unless template_path.directory?
|
45
|
-
next if %w
|
45
|
+
next if %w(. ..).include?(entry.basename.to_s)
|
46
46
|
result << entry.expand_path(templates_source_path)
|
47
47
|
}
|
48
48
|
result
|
data/lib/skippy/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
1
3
|
require 'skippy/app'
|
2
4
|
require 'skippy/command'
|
3
5
|
require 'skippy/group'
|
@@ -41,14 +43,15 @@ class Skippy::CLI < Skippy::Command
|
|
41
43
|
end
|
42
44
|
|
43
45
|
# Verbatim copy from Thor::Runner:
|
44
|
-
# Override Thor#help so it can give information about any class and any
|
46
|
+
# Override Thor#help so it can give information about any class and any
|
47
|
+
# method.
|
45
48
|
#
|
46
49
|
def help(meth = nil)
|
47
|
-
if meth && !
|
50
|
+
if meth && !respond_to?(meth)
|
48
51
|
initialize_thorfiles(meth)
|
49
52
|
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
50
53
|
self.class.handle_no_command_error(command, false) if klass.nil?
|
51
|
-
klass.start(['-h', command].compact, :
|
54
|
+
klass.start(['-h', command].compact, shell: shell)
|
52
55
|
else
|
53
56
|
super
|
54
57
|
end
|
@@ -58,18 +61,22 @@ class Skippy::CLI < Skippy::Command
|
|
58
61
|
# If a command is not found on Thor::Runner, method missing is invoked and
|
59
62
|
# Thor::Runner is then responsible for finding the command in all classes.
|
60
63
|
#
|
61
|
-
def method_missing(meth, *args)
|
64
|
+
def method_missing(meth, *args) # rubocop:disable Style/MethodMissing
|
62
65
|
meth = meth.to_s
|
63
66
|
initialize_thorfiles(meth)
|
64
67
|
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
65
68
|
self.class.handle_no_command_error(command, false) if klass.nil?
|
66
69
|
args.unshift(command) if command
|
67
|
-
klass.start(args, :
|
70
|
+
klass.start(args, shell: shell)
|
68
71
|
end
|
69
72
|
|
70
73
|
# Verbatim copy from Thor::Runner:
|
71
|
-
desc 'list [SEARCH]',
|
72
|
-
|
74
|
+
desc 'list [SEARCH]',
|
75
|
+
"List the available #{$PROGRAM_NAME} commands (--substring means .*SEARCH)"
|
76
|
+
method_options substring: :boolean,
|
77
|
+
group: :string,
|
78
|
+
all: :boolean,
|
79
|
+
debug: :boolean
|
73
80
|
def list(search = '')
|
74
81
|
initialize_thorfiles
|
75
82
|
|
@@ -77,15 +84,13 @@ class Skippy::CLI < Skippy::Command
|
|
77
84
|
search = /^#{search}.*/i
|
78
85
|
group = options[:group] || 'standard'
|
79
86
|
|
80
|
-
klasses = Thor::Base.subclasses.select
|
87
|
+
klasses = Thor::Base.subclasses.select { |k|
|
81
88
|
(options[:all] || k.group == group) && k.namespace =~ search
|
82
|
-
|
89
|
+
}
|
83
90
|
|
84
91
|
display_klasses(false, false, klasses)
|
85
92
|
end
|
86
93
|
|
87
|
-
private
|
88
|
-
|
89
94
|
# Based on Thor::Runner, with exception of program name.
|
90
95
|
def self.banner(command, all = false, subcommand = false)
|
91
96
|
"#{$PROGRAM_NAME} " + command.formatted_usage(self, all, subcommand)
|
@@ -96,6 +101,8 @@ class Skippy::CLI < Skippy::Command
|
|
96
101
|
true
|
97
102
|
end
|
98
103
|
|
104
|
+
private
|
105
|
+
|
99
106
|
# This is one of the places this runner differ from Thor::Runner. It will
|
100
107
|
# instead load files for the current project.
|
101
108
|
#
|
@@ -107,7 +114,16 @@ class Skippy::CLI < Skippy::Command
|
|
107
114
|
return unless project.exist?
|
108
115
|
project.command_files { |filename|
|
109
116
|
unless Thor::Base.subclass_files.keys.include?(File.expand_path(filename))
|
110
|
-
|
117
|
+
begin
|
118
|
+
Thor::Util.load_thorfile(filename, nil, options[:debug])
|
119
|
+
rescue ScriptError, StandardError => error
|
120
|
+
command_path = Pathname.new(filename).relative_path_from(project.path)
|
121
|
+
say "Error loading: #{command_path} (#{error})", :red
|
122
|
+
if options[:debug]
|
123
|
+
say error.inspect, :red
|
124
|
+
say error.backtrace.join("\n"), :red
|
125
|
+
end
|
126
|
+
end
|
111
127
|
end
|
112
128
|
}
|
113
129
|
end
|
@@ -120,15 +136,20 @@ class Skippy::CLI < Skippy::Command
|
|
120
136
|
end
|
121
137
|
|
122
138
|
# Based on Thor::Runner:
|
123
|
-
def display_klasses(_with_modules = false,
|
139
|
+
def display_klasses(_with_modules = false,
|
140
|
+
show_internal = false,
|
141
|
+
klasses = Thor::Base.subclasses)
|
142
|
+
|
124
143
|
unless show_internal
|
125
144
|
klasses -= [
|
126
145
|
Thor, Thor::Runner, Thor::Group,
|
127
|
-
Skippy, Skippy::CLI, Skippy::Command, Skippy::Command::Group
|
146
|
+
Skippy, Skippy::CLI, Skippy::Command, Skippy::Command::Group,
|
128
147
|
]
|
129
148
|
end
|
130
149
|
|
131
|
-
|
150
|
+
if klasses.empty?
|
151
|
+
raise Error, "No #{$PROGRAM_NAME.capitalize} commands available"
|
152
|
+
end
|
132
153
|
|
133
154
|
list = Hash.new { |h, k| h[k] = [] }
|
134
155
|
groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
|
@@ -177,16 +198,16 @@ class Skippy::CLI < Skippy::Command
|
|
177
198
|
# TODO(thomthom): Because of the odd issue with col_width mentioned in
|
178
199
|
# `display_klasses` the table isn't truncated. Can probably re-enable if
|
179
200
|
# the col_width issue is fixed.
|
180
|
-
#print_table(list, :truncate => true, :indent => 2, :colwidth => col_width)
|
201
|
+
# print_table(list, :truncate => true, :indent => 2, :colwidth => col_width)
|
181
202
|
width = (col_width + 2) * 2
|
182
|
-
print_table(list, :
|
203
|
+
print_table(list, indent: 2, colwidth: width)
|
183
204
|
end
|
184
|
-
|
205
|
+
alias display_tasks display_commands
|
185
206
|
|
186
207
|
# Based on Thor::Runner, skipping the yaml stuff:
|
187
208
|
def show_modules
|
188
|
-
info
|
189
|
-
labels = %w
|
209
|
+
info = []
|
210
|
+
labels = %w(Modules Namespaces)
|
190
211
|
|
191
212
|
info << labels
|
192
213
|
info << ['-' * labels[0].size, '-' * labels[1].size]
|
data/lib/skippy/command.rb
CHANGED
@@ -3,12 +3,10 @@ require 'thor'
|
|
3
3
|
module Skippy
|
4
4
|
class Command < Thor
|
5
5
|
|
6
|
-
protected
|
7
|
-
|
8
6
|
# Customize the banner as we don't care for the 'skippy' prefix for each
|
9
7
|
# item in the list.
|
10
|
-
def self.banner(command,
|
11
|
-
|
8
|
+
def self.banner(command, _namespace = nil, subcommand = false)
|
9
|
+
command.formatted_usage(self, true, subcommand).to_s
|
12
10
|
end
|
13
11
|
|
14
12
|
end
|
data/lib/skippy/config.rb
CHANGED
@@ -5,7 +5,7 @@ require 'skippy/error'
|
|
5
5
|
|
6
6
|
class Skippy::Config < Hash
|
7
7
|
|
8
|
-
|
8
|
+
attr_reader :path
|
9
9
|
|
10
10
|
class MissingPathError < Skippy::Error; end
|
11
11
|
|
@@ -14,25 +14,11 @@ class Skippy::Config < Hash
|
|
14
14
|
json = File.read(path)
|
15
15
|
config = JSON.parse(json,
|
16
16
|
symbolize_names: true,
|
17
|
-
object_class: self
|
18
|
-
)
|
17
|
+
object_class: self)
|
19
18
|
else
|
20
|
-
config =
|
19
|
+
config = new
|
21
20
|
end
|
22
|
-
|
23
|
-
config.merge!(defaults) { |_key, value, default|
|
24
|
-
if value.is_a?(Hash) && default.is_a?(Hash)
|
25
|
-
# Deep merge in order to merge nested hashes.
|
26
|
-
# Note: This currently doesn't merge arrays.
|
27
|
-
# http://stackoverflow.com/a/9381776/486990
|
28
|
-
merger = proc { |_k, v1, v2|
|
29
|
-
Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
|
30
|
-
}
|
31
|
-
default.merge(value, &merger)
|
32
|
-
else
|
33
|
-
value || default
|
34
|
-
end
|
35
|
-
}
|
21
|
+
config.merge_defaults(defaults)
|
36
22
|
config.path = path
|
37
23
|
config
|
38
24
|
end
|
@@ -77,7 +63,7 @@ class Skippy::Config < Hash
|
|
77
63
|
if hash.keys.first.is_a?(String)
|
78
64
|
update_from_key_paths(hash)
|
79
65
|
else
|
80
|
-
|
66
|
+
deep_merge!(hash)
|
81
67
|
end
|
82
68
|
self
|
83
69
|
end
|
@@ -86,11 +72,30 @@ class Skippy::Config < Hash
|
|
86
72
|
"#{super}:#{self.class.name}"
|
87
73
|
end
|
88
74
|
|
75
|
+
# @param [Hash] defaults
|
76
|
+
def merge_defaults(defaults)
|
77
|
+
merge!(defaults) { |_key, value, default|
|
78
|
+
if value.is_a?(Hash) && default.is_a?(Hash)
|
79
|
+
# Deep merge in order to merge nested hashes.
|
80
|
+
# Note: This currently doesn't merge arrays.
|
81
|
+
# http://stackoverflow.com/a/9381776/486990
|
82
|
+
merger = proc { |_k, v1, v2|
|
83
|
+
v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2
|
84
|
+
}
|
85
|
+
default.merge(value, &merger)
|
86
|
+
else
|
87
|
+
# TODO(thomthom): Should `merger` include this logic?
|
88
|
+
value || default
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
89
93
|
private
|
90
94
|
|
91
|
-
|
95
|
+
# @param [Hash] hash
|
96
|
+
def deep_merge!(hash)
|
92
97
|
merger = proc { |_key, v1, v2|
|
93
|
-
Hash
|
98
|
+
v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2
|
94
99
|
}
|
95
100
|
merge!(hash, &merger)
|
96
101
|
end
|
@@ -105,7 +110,7 @@ class Skippy::Config < Hash
|
|
105
110
|
if key_path.is_a?(Symbol)
|
106
111
|
[key_path]
|
107
112
|
else
|
108
|
-
key_path.split('/').map
|
113
|
+
key_path.split('/').map(&:intern)
|
109
114
|
end
|
110
115
|
end
|
111
116
|
|
@@ -5,38 +5,38 @@ module Skippy::ConfigAccessors
|
|
5
5
|
|
6
6
|
private
|
7
7
|
|
8
|
-
def config_attr(*symbols, key: nil, type: nil)
|
9
|
-
config_attr_reader(*symbols, key: key, type: type)
|
8
|
+
def config_attr(*symbols, key: nil, default: nil, type: nil)
|
9
|
+
config_attr_reader(*symbols, key: key, type: type, default: default)
|
10
10
|
config_attr_writer(*symbols, key: key, type: type)
|
11
11
|
nil
|
12
12
|
end
|
13
13
|
|
14
|
-
def config_attr_reader(*symbols, key: nil, type: nil)
|
15
|
-
|
14
|
+
def config_attr_reader(*symbols, key: nil, default: nil, type: nil)
|
15
|
+
class_eval do
|
16
16
|
symbols.each { |symbol|
|
17
17
|
raise TypeError unless symbol.is_a?(Symbol)
|
18
|
-
define_method(symbol)
|
19
|
-
value = @config.get(key || symbol)
|
18
|
+
define_method(symbol) do
|
19
|
+
value = @config.get(key || symbol, default)
|
20
20
|
value = type.new(value) if type && !value.is_a?(type)
|
21
21
|
value
|
22
|
-
|
22
|
+
end
|
23
23
|
}
|
24
|
-
|
24
|
+
end
|
25
25
|
nil
|
26
26
|
end
|
27
27
|
|
28
28
|
def config_attr_writer(*symbols, key: nil, type: nil)
|
29
|
-
|
29
|
+
class_eval do
|
30
30
|
symbols.each { |symbol|
|
31
31
|
raise TypeError unless symbol.is_a?(Symbol)
|
32
32
|
symbol_set = "#{symbol}=".intern
|
33
|
-
define_method(symbol_set)
|
33
|
+
define_method(symbol_set) do |value|
|
34
34
|
value = type.new(value) if type && !value.is_a?(type)
|
35
35
|
@config.set(key || symbol, value)
|
36
36
|
value
|
37
|
-
|
37
|
+
end
|
38
38
|
}
|
39
|
-
|
39
|
+
end
|
40
40
|
nil
|
41
41
|
end
|
42
42
|
|
data/lib/skippy/group.rb
CHANGED
@@ -5,12 +5,10 @@ require 'skippy/command'
|
|
5
5
|
module Skippy
|
6
6
|
class Command::Group < Thor::Group
|
7
7
|
|
8
|
-
protected
|
9
|
-
|
10
8
|
# Customize the banner as we don't care for the 'skippy' prefix for each
|
11
9
|
# item in the list.
|
12
10
|
def self.banner
|
13
|
-
|
11
|
+
self_command.formatted_usage(self, false).to_s
|
14
12
|
end
|
15
13
|
|
16
14
|
end
|
data/lib/skippy/helpers/file.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Skippy::Helpers
|
2
2
|
module File
|
3
3
|
|
4
|
+
extend self
|
5
|
+
|
4
6
|
# @param [Pathname]
|
5
7
|
# @return [Array<Pathname>]
|
6
8
|
def directories(pathname)
|
7
9
|
return [] unless pathname.exist?
|
8
|
-
pathname.children.select
|
9
|
-
child.directory?
|
10
|
-
}
|
10
|
+
pathname.children.select(&:directory?)
|
11
11
|
end
|
12
12
|
|
13
13
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'skippy/lib_source'
|
2
|
+
require 'skippy/library'
|
3
|
+
require 'skippy/project'
|
4
|
+
|
5
|
+
class Skippy::LibraryInstaller
|
6
|
+
|
7
|
+
attr_reader :project, :source
|
8
|
+
|
9
|
+
# @param [Skippy::Project] project
|
10
|
+
# @param [Skippy::LibrarySource] source
|
11
|
+
def initialize(project, lib_source)
|
12
|
+
@project = project
|
13
|
+
@source = lib_source
|
14
|
+
@messager = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_status(&block)
|
18
|
+
@messager = block
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Skippy::Library]
|
22
|
+
def install
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# @param [Symbol] type
|
29
|
+
# @param [String] message
|
30
|
+
def status(type, message)
|
31
|
+
@messager.call(type, message) if @messager
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param [String] message
|
35
|
+
def info(message)
|
36
|
+
status(:info, message)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param [String] message
|
40
|
+
def warning(message)
|
41
|
+
status(:warning, "Warning: #{message}")
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Pathname]
|
45
|
+
def path
|
46
|
+
project.libraries.path
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'git'
|
2
|
+
require 'naturally'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
require 'skippy/error'
|
6
|
+
require 'skippy/installer'
|
7
|
+
require 'skippy/library'
|
8
|
+
|
9
|
+
module Skippy
|
10
|
+
|
11
|
+
class BranchNotFound < Skippy::Error; end
|
12
|
+
class TagNotFound < Skippy::Error; end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class Skippy::GitLibraryInstaller < Skippy::LibraryInstaller
|
17
|
+
|
18
|
+
# @return [Skippy::Library]
|
19
|
+
def install
|
20
|
+
info "Installing #{source.basename} from #{source.origin}..."
|
21
|
+
target = path.join(source.lib_path)
|
22
|
+
previous_commit = nil
|
23
|
+
if target.directory?
|
24
|
+
git, previous_commit = update_repository(target)
|
25
|
+
else
|
26
|
+
git = clone_repository(source.origin, target)
|
27
|
+
end
|
28
|
+
begin
|
29
|
+
checkout_branch(git, source.branch) if source.branch
|
30
|
+
checkout_tag(git, source.requirement) unless edge_version?(source.requirement)
|
31
|
+
rescue Skippy::Error
|
32
|
+
git.checkout(previous_commit) if previous_commit
|
33
|
+
raise
|
34
|
+
end
|
35
|
+
library = Skippy::Library.new(target, source: source)
|
36
|
+
library
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @param [URI] uri
|
42
|
+
# @param [Pathname] target
|
43
|
+
# @return [Git::Base]
|
44
|
+
def clone_repository(uri, target)
|
45
|
+
info 'Cloning...'
|
46
|
+
Git.clone(uri, target.basename, path: target.parent)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param [Pathname] target
|
50
|
+
# @return [Array(Git::Base, Git::Commit)]
|
51
|
+
def update_repository(target)
|
52
|
+
info 'Updating...'
|
53
|
+
library = Skippy::Library.new(target)
|
54
|
+
info "Current version: #{library.version}"
|
55
|
+
git = Git.open(target)
|
56
|
+
previous_commit = git.object('HEAD^').class
|
57
|
+
git.reset_hard
|
58
|
+
git.pull
|
59
|
+
[git, previous_commit]
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param [Git::Base]
|
63
|
+
# @param [String] branch
|
64
|
+
def checkout_branch(git, branch)
|
65
|
+
branches = git.braches.map(&:name)
|
66
|
+
info "Branches: #{branches.inspect}"
|
67
|
+
unless branches.include?(branch)
|
68
|
+
raise Skippy::BranchNotFound, "Found no branch named: '#{branch}'"
|
69
|
+
end
|
70
|
+
git.checkout(branch)
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param [Git::Base]
|
75
|
+
# @param [String] version
|
76
|
+
def checkout_tag(git, version)
|
77
|
+
tags = Naturally.sort_by(git.tags, :name)
|
78
|
+
tag = latest_version?(version) ? tags.last : resolve_tag(tags, version)
|
79
|
+
raise Skippy::TagNotFound, "Found no version: '#{version}'" if tag.nil?
|
80
|
+
git.checkout(tag)
|
81
|
+
# Verify the library version with the tagged version.
|
82
|
+
target = path.join(source.lib_path)
|
83
|
+
library = Skippy::Library.new(target)
|
84
|
+
unless library.version.casecmp(tag.name).zero?
|
85
|
+
warning "skippy.json version (#{library.version}) differ from "\
|
86
|
+
"tagged version (#{tag.name})"
|
87
|
+
end
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Resolve version numbers like RubyGem.
|
92
|
+
#
|
93
|
+
# @param [Array<Git::Tag>] tags List of tags sorted with newest first
|
94
|
+
# @param [String] version
|
95
|
+
# @return [Git::Tag]
|
96
|
+
def resolve_tag(tags, version)
|
97
|
+
requirement = Gem::Requirement.new(version)
|
98
|
+
tags.reverse.find { |tag|
|
99
|
+
next false unless Gem::Version.correct?(tag.name)
|
100
|
+
tag_version = Gem::Version.new(tag.name)
|
101
|
+
requirement.satisfied_by?(tag_version)
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param [String] version
|
106
|
+
def edge_version?(version)
|
107
|
+
version && version.casecmp('edge').zero?
|
108
|
+
end
|
109
|
+
|
110
|
+
# @param [String] version
|
111
|
+
def latest_version?(version)
|
112
|
+
version.nil? || version.casecmp('latest').zero?
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|