claide-plugins 0.9.0
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 +7 -0
- data/.gitignore +41 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_cocoapods.yml +116 -0
- data/.tm_properties +2 -0
- data/.travis.yml +24 -0
- data/CHANGELOG.md +113 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +44 -0
- data/Rakefile +55 -0
- data/claide-plugins.gemspec +32 -0
- data/lib/claide/command/gem_helper.rb +120 -0
- data/lib/claide/command/gem_index_cache.rb +87 -0
- data/lib/claide/command/plugins.rb +47 -0
- data/lib/claide/command/plugins/create.rb +121 -0
- data/lib/claide/command/plugins/list.rb +34 -0
- data/lib/claide/command/plugins/search.rb +60 -0
- data/lib/claide/command/plugins_config.rb +35 -0
- data/lib/claide/command/plugins_helper.rb +134 -0
- data/lib/claide/executable.rb +116 -0
- data/lib/claide_plugin.rb +1 -0
- data/lib/claide_plugins.rb +3 -0
- data/spec/command/gem_helper_spec.rb +41 -0
- data/spec/command/gem_index_cache_spec.rb +38 -0
- data/spec/command/plugins/create_spec.rb +89 -0
- data/spec/command/plugins/list_spec.rb +29 -0
- data/spec/command/plugins/search_spec.rb +55 -0
- data/spec/command/plugins_helper_spec.rb +33 -0
- data/spec/command/plugins_spec.rb +45 -0
- data/spec/fixtures/claide-foo1.gemspec +10 -0
- data/spec/fixtures/claide-foo2.gemspec +9 -0
- data/spec/fixtures/plugins.json +22 -0
- data/spec/fixtures/unprefixed.gemspec +10 -0
- data/spec/spec_helper.rb +93 -0
- metadata +165 -0
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Bootstrap
|
2
|
+
#-----------------------------------------------------------------------------#
|
3
|
+
|
4
|
+
task :bootstrap do
|
5
|
+
if system('which bundle')
|
6
|
+
sh 'bundle install'
|
7
|
+
else
|
8
|
+
$stderr.puts "\033[0;31m" \
|
9
|
+
"[!] Please install the bundler gem manually:\n" \
|
10
|
+
' $ [sudo] gem install bundler' \
|
11
|
+
"\e[0m"
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
|
18
|
+
require 'bundler/gem_tasks'
|
19
|
+
|
20
|
+
task :default => 'spec'
|
21
|
+
|
22
|
+
# Spec
|
23
|
+
#-----------------------------------------------------------------------------#
|
24
|
+
|
25
|
+
desc 'Runs all the specs'
|
26
|
+
task :spec do
|
27
|
+
start_time = Time.now
|
28
|
+
sh "bundle exec bacon #{specs('**')}"
|
29
|
+
duration = Time.now - start_time
|
30
|
+
puts "Tests completed in #{duration}s"
|
31
|
+
Rake::Task['rubocop'].invoke
|
32
|
+
end
|
33
|
+
|
34
|
+
def specs(dir)
|
35
|
+
FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
|
36
|
+
end
|
37
|
+
|
38
|
+
# Rubocop
|
39
|
+
#-----------------------------------------------------------------------------#
|
40
|
+
|
41
|
+
desc 'Checks code style'
|
42
|
+
task :rubocop do
|
43
|
+
require 'rubocop'
|
44
|
+
cli = RuboCop::CLI.new
|
45
|
+
result = cli.run(FileList['{spec,lib}/**/*.rb'])
|
46
|
+
abort('RuboCop failed!') unless result == 0
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
rescue LoadError
|
51
|
+
$stderr.puts "\033[0;31m" \
|
52
|
+
'[!] Some Rake tasks haven been disabled because the environment' \
|
53
|
+
' couldn’t be loaded. Be sure to run `rake bootstrap` first.' \
|
54
|
+
"\e[0m"
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'claide_plugins.rb'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'claide-plugins'
|
8
|
+
spec.version = CLAidePlugins::VERSION
|
9
|
+
spec.authors = ['David Grandinetti', 'Olivier Halligon']
|
10
|
+
spec.summary = %q{CLAide plugin which shows info about available CLAide plugins.}
|
11
|
+
spec.description = <<-DESC
|
12
|
+
This CLAide plugin shows information about all available CLAide plugins
|
13
|
+
(yes, this is very meta!).
|
14
|
+
This plugin adds the "plugins" subcommand to a binary so that you can list
|
15
|
+
all plugins (registered in the reference JSON hosted at CocoaPods/cocoapods-plugins)
|
16
|
+
DESC
|
17
|
+
spec.homepage = 'https://github.com/cocoapods/claide-plugins'
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.files = `git ls-files`.split($/)
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_runtime_dependency 'nap', '~> 1.0'
|
25
|
+
spec.add_runtime_dependency 'cork', '~> 0'
|
26
|
+
spec.add_runtime_dependency 'open4', '~> 1.3'
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
29
|
+
spec.add_development_dependency 'rake'
|
30
|
+
|
31
|
+
spec.required_ruby_version = '>= 2.0.0'
|
32
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'claide/command/gem_index_cache'
|
2
|
+
|
3
|
+
module CLAide
|
4
|
+
class Command
|
5
|
+
# This module is used by Command::PluginsHelper to download the Gem
|
6
|
+
# Specification data, check if a Gem is installed, and provide info
|
7
|
+
# on all versions of a Gem.
|
8
|
+
#
|
9
|
+
module GemHelper
|
10
|
+
# A GemIndexCache to manage downloading/caching the spec index.
|
11
|
+
#
|
12
|
+
@cache = nil
|
13
|
+
|
14
|
+
# Getter for GemIndexCache
|
15
|
+
#
|
16
|
+
# @return [GemIndexCache] a new or memoized GemIndexCache
|
17
|
+
#
|
18
|
+
def self.cache
|
19
|
+
@cache ||= GemIndexCache.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# Instantiate a cache and download the spec index if it has
|
23
|
+
# not already been done.
|
24
|
+
#
|
25
|
+
def self.download_and_cache_specs
|
26
|
+
cache.download_and_cache_specs
|
27
|
+
end
|
28
|
+
|
29
|
+
# Tells if a gem is installed
|
30
|
+
#
|
31
|
+
# @param [String] gem_name
|
32
|
+
# The name of the plugin gem to test
|
33
|
+
#
|
34
|
+
# @param [String] version_string
|
35
|
+
# An optional version string, used to check if a specific
|
36
|
+
# version of a gem is installed
|
37
|
+
#
|
38
|
+
# @return [Bool] true if the gem is installed, false otherwise.
|
39
|
+
#
|
40
|
+
def self.gem_installed?(gem_name, version_string = nil)
|
41
|
+
version = Gem::Version.new(version_string) if version_string
|
42
|
+
|
43
|
+
if Gem::Specification.respond_to?(:find_all_by_name)
|
44
|
+
gems = Gem::Specification.find_all_by_name(gem_name)
|
45
|
+
return !gems.empty? unless version
|
46
|
+
gems.each { |gem| return true if gem.version == version }
|
47
|
+
false
|
48
|
+
else
|
49
|
+
dep = Gem::Dependency.new(gem_name, version_string)
|
50
|
+
!Gem.source_index.search(dep).empty?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get the version of a gem that is installed locally. If more than
|
55
|
+
# one version is installed, this returns the first version found,
|
56
|
+
# which MAY not be the highest/newest version.
|
57
|
+
#
|
58
|
+
# @return [String] The version of the gem that is installed,
|
59
|
+
# or nil if it is not installed.
|
60
|
+
#
|
61
|
+
def self.installed_version(gem_name)
|
62
|
+
if Gem::Specification.respond_to?(:find_all_by_name)
|
63
|
+
gem = Gem::Specification.find_all_by_name(gem_name).first
|
64
|
+
else
|
65
|
+
dep = Gem::Dependency.new(gem_name)
|
66
|
+
gem = Gem.source_index.search(dep).first
|
67
|
+
end
|
68
|
+
gem ? gem.version.to_s : nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a string containing all versions of a plugin,
|
72
|
+
# colored to indicate if a specific version is installed
|
73
|
+
# locally.
|
74
|
+
#
|
75
|
+
# @param [String] plugin_name
|
76
|
+
# The name of the plugin gem
|
77
|
+
#
|
78
|
+
# @param [GemIndexCache] index_cache
|
79
|
+
# Optional index cache can be passed in, otherwise
|
80
|
+
# the module instance is used.
|
81
|
+
#
|
82
|
+
# @return [String] a string containing a comma separated
|
83
|
+
# concatenation of all versions of a plugin
|
84
|
+
# that were found on rubygems.org
|
85
|
+
#
|
86
|
+
def self.versions_string(plugin_name, index_cache = @cache)
|
87
|
+
name_tuples = index_cache.specs_with_name(plugin_name)
|
88
|
+
sorted_versions = name_tuples.sort_by(&:version)
|
89
|
+
version_strings = colorize_versions(sorted_versions)
|
90
|
+
version_strings.join ', '
|
91
|
+
end
|
92
|
+
|
93
|
+
#----------------#
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Colorize an Array of version strings so versions that are installed
|
98
|
+
# are green and uninstalled versions are yellow.
|
99
|
+
#
|
100
|
+
# @param [Array] versions
|
101
|
+
# sorted array of Gem::NameTuples representing all versions of
|
102
|
+
# a plugin gem.
|
103
|
+
#
|
104
|
+
# @return [Array] An array of strings, each one being the version
|
105
|
+
# string of the same plugin
|
106
|
+
#
|
107
|
+
def self.colorize_versions(versions)
|
108
|
+
colored_strings = []
|
109
|
+
versions.reverse_each do |name_tuple|
|
110
|
+
if gem_installed?(name_tuple.name, name_tuple.version.to_s)
|
111
|
+
colored_strings << name_tuple.version.to_s.green
|
112
|
+
else
|
113
|
+
colored_strings << name_tuple.version.to_s.yellow
|
114
|
+
end
|
115
|
+
end
|
116
|
+
colored_strings
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'claide/command/gem_helper'
|
2
|
+
|
3
|
+
module CLAide
|
4
|
+
class Command
|
5
|
+
# This class is used by Command::GemsHelper to download the Gem
|
6
|
+
# Specification index from rubygems.org and provide info about
|
7
|
+
# the index.
|
8
|
+
#
|
9
|
+
class GemIndexCache
|
10
|
+
# A memoized hash of all the rubygem specs. If it is nil, the specs will
|
11
|
+
# be downloaded, which will take a few seconds to download.
|
12
|
+
#
|
13
|
+
# @return [Hash] The hash of all rubygems
|
14
|
+
#
|
15
|
+
def specs
|
16
|
+
@specs ||= download_specs
|
17
|
+
end
|
18
|
+
|
19
|
+
# Alias to make the initial caching process more readable.
|
20
|
+
#
|
21
|
+
alias_method :download_and_cache_specs, :specs
|
22
|
+
|
23
|
+
# Get an Array of Gem::NameTuple objects that match a given
|
24
|
+
# spec name.
|
25
|
+
#
|
26
|
+
# @param [String] name
|
27
|
+
# The name of the gem to match on (e.g. 'cocoapods-try')
|
28
|
+
#
|
29
|
+
# @return [Array] Array of Gem::NameTuple that match the name
|
30
|
+
#
|
31
|
+
def specs_with_name(name)
|
32
|
+
matching_specs = @specs.select do |spec|
|
33
|
+
spec[0].name == name
|
34
|
+
end
|
35
|
+
|
36
|
+
name_tuples = []
|
37
|
+
matching_specs.each do |(name_tuple, _)|
|
38
|
+
name_tuples << name_tuple
|
39
|
+
end
|
40
|
+
|
41
|
+
name_tuples
|
42
|
+
end
|
43
|
+
|
44
|
+
#----------------#
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Force the rubygem spec index file
|
49
|
+
#
|
50
|
+
# @return [Hash] The hash of all rubygems
|
51
|
+
#
|
52
|
+
def download_specs
|
53
|
+
UI.puts 'Downloading Rubygem specification index...'
|
54
|
+
fetcher = Gem::SpecFetcher.fetcher
|
55
|
+
results, errors = fetcher.available_specs(:released)
|
56
|
+
|
57
|
+
unless errors.empty?
|
58
|
+
UI.puts 'Error downloading Rubygem specification index: ' +
|
59
|
+
errors.first.error.to_s
|
60
|
+
return []
|
61
|
+
end
|
62
|
+
|
63
|
+
flatten_fetcher_results(results)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Flatten the dictionary returned from Gem::SpecFetcher
|
67
|
+
# to a simple array.
|
68
|
+
#
|
69
|
+
# @param [Hash] results
|
70
|
+
# the hash returned from the call to
|
71
|
+
# Gem::SpecFetcher.available_specs()
|
72
|
+
#
|
73
|
+
# @return [Array] Array of all spec results
|
74
|
+
#
|
75
|
+
def flatten_fetcher_results(results)
|
76
|
+
specs = []
|
77
|
+
results.each do |source, source_specs|
|
78
|
+
source_specs.each do |tuple|
|
79
|
+
specs << [tuple, source]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
specs
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rest'
|
2
|
+
require 'json'
|
3
|
+
require 'cork'
|
4
|
+
require 'claide'
|
5
|
+
require 'claide/command/plugins_config'
|
6
|
+
|
7
|
+
UI = Cork::Board.new
|
8
|
+
|
9
|
+
module CLAide
|
10
|
+
module Plugins
|
11
|
+
class << self
|
12
|
+
attr_accessor :config
|
13
|
+
end
|
14
|
+
# set a default configuration that will work with claide-plugins
|
15
|
+
self.config = Configuration.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Indicates a runtime error **not** caused by a bug.
|
19
|
+
#
|
20
|
+
class PlainInformative < StandardError; end
|
21
|
+
|
22
|
+
# Indicates a user error.
|
23
|
+
#
|
24
|
+
class Informative < PlainInformative; end
|
25
|
+
|
26
|
+
class Command
|
27
|
+
# The claide plugins command.
|
28
|
+
#
|
29
|
+
class Plugins < Command
|
30
|
+
require 'claide/command/plugins/list'
|
31
|
+
require 'claide/command/plugins/search'
|
32
|
+
require 'claide/command/plugins/create'
|
33
|
+
|
34
|
+
self.abstract_command = true
|
35
|
+
self.default_subcommand = 'list'
|
36
|
+
|
37
|
+
self.summary = 'Show available plugins'
|
38
|
+
self.description = <<-DESC
|
39
|
+
Lists or searches the available plugins
|
40
|
+
and show if you have them installed or not.
|
41
|
+
|
42
|
+
Also allows you to quickly create a new
|
43
|
+
plugin using a provided template.
|
44
|
+
DESC
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'claide/command/plugins_helper'
|
2
|
+
require 'claide/executable'
|
3
|
+
|
4
|
+
module CLAide
|
5
|
+
class Command
|
6
|
+
class Plugins
|
7
|
+
# The create subcommand. Used to create a new plugin using either the
|
8
|
+
# default template (CocoaPods/cocoapods-plugin-template) or a custom
|
9
|
+
# template
|
10
|
+
#
|
11
|
+
class Create < Plugins
|
12
|
+
NAME_PREFIX = 'claide-'
|
13
|
+
|
14
|
+
self.summary = 'Creates a new plugin'
|
15
|
+
self.description = <<-DESC
|
16
|
+
Creates a scaffold for the development of a new plugin
|
17
|
+
named `NAME` according to the CocoaPods best practices.
|
18
|
+
|
19
|
+
If a `TEMPLATE_URL`, pointing to a git repo containing a
|
20
|
+
compatible template, is specified, it will be used
|
21
|
+
in place of the default one.
|
22
|
+
DESC
|
23
|
+
|
24
|
+
self.arguments = [
|
25
|
+
CLAide::Argument.new('NAME', true),
|
26
|
+
CLAide::Argument.new('TEMPLATE_URL', false),
|
27
|
+
]
|
28
|
+
|
29
|
+
def initialize(argv)
|
30
|
+
@name = argv.shift_argument
|
31
|
+
unless @name.nil? || @name.empty? || @name.start_with?(NAME_PREFIX)
|
32
|
+
@name = NAME_PREFIX + @name.dup
|
33
|
+
end
|
34
|
+
@template_url = argv.shift_argument
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate!
|
39
|
+
super
|
40
|
+
if @name.nil? || @name.empty?
|
41
|
+
help! 'A name for the plugin is required.'
|
42
|
+
end
|
43
|
+
|
44
|
+
help! 'The plugin name cannot contain spaces.' if @name.match(/\s/)
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
clone_template
|
49
|
+
configure_template
|
50
|
+
show_reminder
|
51
|
+
end
|
52
|
+
|
53
|
+
#----------------------------------------#
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# !@group Private helpers
|
58
|
+
|
59
|
+
extend CLAide::Executable
|
60
|
+
executable :git
|
61
|
+
|
62
|
+
TEMPLATE_BASE_URL = 'https://github.com/CocoaPods/'
|
63
|
+
TEMPLATE_REPO = TEMPLATE_BASE_URL + 'cocoapods-plugin-template.git'
|
64
|
+
TEMPLATE_INFO_URL = TEMPLATE_BASE_URL + 'cocoapods-plugin-template'
|
65
|
+
|
66
|
+
# Clones the template from the remote in the working directory using
|
67
|
+
# the name of the plugin.
|
68
|
+
#
|
69
|
+
# @return [void]
|
70
|
+
#
|
71
|
+
def clone_template
|
72
|
+
UI.section("-> Creating `#{@name}` plugin") do
|
73
|
+
UI.notice "using template '#{template_repo_url}'"
|
74
|
+
command = ['clone', template_repo_url, @name]
|
75
|
+
if method(:git!).arity == -1
|
76
|
+
git! command
|
77
|
+
else
|
78
|
+
# TODO: delete this conditional and use the other branch when
|
79
|
+
# 0.5.0 is released
|
80
|
+
require 'shellwords'
|
81
|
+
git! command.map(&:to_s).map(&:shellescape).join(' ')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Runs the template configuration utilities.
|
87
|
+
#
|
88
|
+
# @return [void]
|
89
|
+
#
|
90
|
+
def configure_template
|
91
|
+
UI.section('-> Configuring template') do
|
92
|
+
Dir.chdir(@name) do
|
93
|
+
if File.file? 'configure'
|
94
|
+
system "./configure #{@name}"
|
95
|
+
else
|
96
|
+
UI.warn 'Template does not have a configure file.'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Checks if a template URL is given else returns the TEMPLATE_REPO URL
|
103
|
+
#
|
104
|
+
# @return String
|
105
|
+
#
|
106
|
+
def template_repo_url
|
107
|
+
@template_url || TEMPLATE_REPO
|
108
|
+
end
|
109
|
+
|
110
|
+
# Shows a reminder to the plugin author to make a Pull Request
|
111
|
+
# in order to update plugins.json once the plugin is released
|
112
|
+
#
|
113
|
+
def show_reminder
|
114
|
+
repo = PluginsHelper.plugins_raw_url
|
115
|
+
UI.notice "Don't forget to create a Pull Request on #{repo}\n" \
|
116
|
+
' to add your plugin to the plugins.json file once it is released!'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|