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.
@@ -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