Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Major refactoring, cleanup and add manager for dependencies

  • Loading branch information...
commit 8aa6bc36358e3ff84cb77cf23bc99bc88446b44b 1 parent d58be4c
@nesquena nesquena authored
View
2  example/Vendors.lock
@@ -1,3 +1,3 @@
three20 | https://github.com/facebook/three20.git | 0e27b65cb219744383181c19ac24d24ce312269e
-asi-http-request | https://github.com/pokeb/asi-http-request.git | a879b8ec0466bc1e2ec0f2a5ebbd19bcb1d3dab3
+asi-http-request | https://github.com/pokeb/asi-http-request.git | 90e5fbce17d66e5341f105c1eb26133a01686838
JSONKit | https://github.com/johnezang/JSONKit.git | c2146ffeb10d92bfa1537d2033a3235825d1b261
1  example/vendored/JSONKit
@@ -0,0 +1 @@
+Subproject commit c2146ffeb10d92bfa1537d2033a3235825d1b261
1  example/vendored/asi-http-request
@@ -0,0 +1 @@
+Subproject commit 90e5fbce17d66e5341f105c1eb26133a01686838
1  example/vendored/three20
@@ -0,0 +1 @@
+Subproject commit 0e27b65cb219744383181c19ac24d24ce312269e
View
1  lib/vendor.rb
@@ -6,6 +6,7 @@
require File.expand_path(File.dirname(__FILE__) + '/vendor/library')
require File.expand_path(File.dirname(__FILE__) + '/vendor/source')
require File.expand_path(File.dirname(__FILE__) + '/vendor/dependency_file')
+require File.expand_path(File.dirname(__FILE__) + '/vendor/lock_file')
require File.expand_path(File.dirname(__FILE__) + '/vendor/manager')
require File.expand_path(File.dirname(__FILE__) + '/vendor/cli')
Dir[File.expand_path(File.dirname(__FILE__) + '/vendor/libraries/*.rb')].each do |lib|
View
20 lib/vendor/class_property.rb
@@ -1,5 +1,24 @@
+=begin
+
+Used to define getter/setter properties at the class level
+
+class Example
+ include Vendor::ClassProperty
+
+ class_property :name
+ # Example.name("foo", "bar")
+ # Example.name => ["foo", "bar"]
+ # @example.name => ["foo", "bar"]
+end
+
+Used primarily for simple DSLs when defining class values
+
+=end
+
module Vendor
module ClassProperty
+
+ # Define getter/setter properties at the class level
def class_property(name)
self.metaclass.instance_eval do
define_method(name) do |*args|
@@ -13,6 +32,7 @@ def class_property(name)
end
end
+ # Creates instance level method returning same value
define_method(name) do
self.class.send(name)
end
View
29 lib/vendor/cli.rb
@@ -1,16 +1,15 @@
+# Thor CLI running `vendor` binary
module Vendor
class Cli < Thor
include Thor::Actions
- include Vendor::Helpers
# vendor install --path . --file Vendors
desc "install", "Installs the dependencies specified in the Vendors file"
- method_option :file, :default => "Vendors", :aliases => "-f"
- method_option :path, :default => Dir.pwd, :aliases => "-p"
+ method_option :file, :default => "./Vendors", :aliases => "-f"
+ method_option :path, :default => ".", :aliases => "-p"
def install
- depfile = Vendor::DependencyFile.new(File.join(options[:path], options[:file]))
- depfile.vendor!
- depfile.lock!
+ manager = Vendor::Manager.new(options[:path], :vendors_file_path => options[:file])
+ manager.install!
say "Vendored libraries have been installed", :green
end # install
@@ -23,29 +22,25 @@ def update
# vendor list
desc "list", "Lists the dependencies specified for this project"
- method_option :file, :default => "Vendors", :aliases => "-f"
- method_option :path, :default => Dir.pwd, :aliases => "-p"
def list
- depfile = Vendor::DependencyFile.new(File.join(options[:path], options[:file]))
+ manager = Vendor::Manager.new(Dir.pwd)
say "Dependencies:\n"
- depfile.locked_libraries.each do |lib|
- say " #{lib[:name]} [#{lib[:revision]}] at (#{lib[:source]})", :yellow
+ manager.locked_libraries.each do |lib|
+ say " #{lib}", :yellow
end
end
# vendor check
desc "check", "Checks which dependencies are satisfied"
- method_option :file, :default => "Vendors", :aliases => "-f"
- method_option :path, :default => Dir.pwd, :aliases => "-p"
def check
- depfile = Vendor::DependencyFile.new(File.join(options[:path], options[:file]))
- missing = depfile.missing_libraries
+ manager = Vendor::Manager.new(Dir.pwd)
+ missing = manager.missing_libraries
if missing.any?
puts "Missing:\n"
- missing.each { |lib| say "#{lib[:name]} (#{lib[:source]}) [#{lib[:revision]}]", :yellow }
+ missing.each { |lib| say lib, :yellow }
else # all met
say "All dependencies have been satisfied", :green
end
- end
+ end # check
end # CLI
end
View
57 lib/vendor/dependency_file.rb
@@ -1,16 +1,16 @@
+# Represents the dependency "Vendors" file declaring required libraries
+
module Vendor
class DependencyFile
include Vendor::Helpers
attr_reader :sources
+ # Vendor::DependencyFile.new("path/to/project/Vendors")
def initialize(file_path)
@file_path = file_path
- @folder = File.dirname(@file_path)
- @vendored_path = File.join(@folder, "vendored")
@text = File.read(file_path)
- @sources = []
- @libs = []
+ @sources, @libs = [], []
self.instance_eval(@text)
end
@@ -26,53 +26,12 @@ def lib(name, options={})
@libs << options.merge(:name => name)
end
- # Returns libraries based on specified information and formulae
+ # Returns library instances based on specified Vendors information
+ # @depfile.libraries => [<Library>, <Library>]
def libraries
@_libraries ||= @libs.map do |lib_data|
- if lib_data[:git]
- Vendor::Library.new(lib_data.delete(:name), lib_data)
- else # assume local source
- klazz_name = lib_data[:class] || camelize_word(lib_data[:name].gsub(/-/, '_'))
- klazz = eval(klazz_name) rescue nil
- raise "Cannot find formula #{klazz_name.inspect}" unless klazz
- klazz.new(lib_data[:name])
- end
- end # libs
- end # libraries
-
- # Vendors the various libraries to the specified path
- def vendor!
- FileUtils.mkdir_p(@vendored_path)
- self.sources.each { |source| source.fetch }
- self.libraries.each { |library| library.fetch(@vendored_path) }
- end
-
- # Outputs a lock file with specific versions
- def lock!
- f = File.new(@file_path + ".lock", 'w')
- self.libraries.each do |library|
- f.puts "#{library.name} | #{library.source} | #{library.revision}"
+ resolve_library(lib_data)
end
- f.close
- end
-
- # Returns libraries specified in Vendor.lock
- def locked_libraries
- return self.libraries.map { |lib| lib.to_hash } unless File.exist?(@file_path + ".lock")
- File.read(@file_path + ".lock").split("\n").map do |file_data|
- split_data = file_data.split(" | ")
- { :name => split_data.first, :source => split_data[1], :revision => split_data.last }
- end
- end
-
- # Returns libraries that are missing from local installation
- def missing_libraries
- return self.libraries.map { |lib| lib.to_hash } unless File.exist?(@file_path + ".lock")
- self.locked_libraries.select do |lib|
- local_path = File.join(@vendored_path, lib[:name])
- installed = self.libraries.find { |l| l.name == lib[:name] }
- installed.nil? || (installed.revision(local_path) != lib[:revision])
- end
- end
+ end # libraries
end # DependencyFile
end # Vendor
View
20 lib/vendor/helpers.rb
@@ -1,7 +1,25 @@
+# Vendor helpers for the different library functions
+
module Vendor
module Helpers
+ # resolve_library(:name => "foo", :git => "http://path/to/repo.git") => <Library name=foo>
+ # resolve_library(:name => "baz", :class => "BazLib") => <BazLib name=baz>
+ def resolve_library(lib_data)
+ lib_data = lib_data.dup
+ if lib_data[:git] # simple git library
+ Vendor::Library.new(lib_data.delete(:name), lib_data)
+ else # defined library
+ klazz_name = lib_data[:class] || camelize_word(lib_data[:name].gsub(/-/, '_'))
+ klazz = eval(klazz_name) rescue nil
+ raise "Cannot find formula #{klazz_name.inspect}" unless klazz
+ klazz.new(lib_data[:name], lib_data)
+ end # find library instance
+ end
+
+ # camelize_word("lower_case_lib") => "LowerCaseLib"
def camelize_word(lower_case_and_underscored_word)
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) {
+ "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
end
end
end
View
49 lib/vendor/library.rb
@@ -9,43 +9,52 @@ class Library
class_property :linker_flags
class_property :vendors
- attr_reader :name, :local_path
+ attr_reader :name, :source, :local_path
# Vendor::Library.new("three20", [<source>, <source>], { })
+ # Construct new instance of a library
def initialize(name, options={})
@name = name
- @options = { :git => self.class.source }.merge(options)
+ @options = options
+ @source = @options[:git] || self.class.source
+ @revision = @options[:revision]
end
- def fetch(target_path)
- if @options.has_key?(:git)
- self.fetch_git(target_path)
+ # Downloads remote library to vendored path
+ # @library.fetch("/path/to/project/vendored")
+ def fetch(vendored_path)
+ if @source && @source =~ /\.git$/
+ self.fetch_git(vendored_path)
end # fetch_git
end # fetch
- def source
- @options[:git]
- end
-
- def revision(target_path = self.local_path)
- return nil unless target_path
- return nil unless File.exist?(target_path.to_s + "/.git")
- @grit = Grit::Repo.new(target_path)
- @grit.commits('master', 1).first.sha
+ # Retrieves the revision number for this library
+ # @library.revision => "c1b3hg7"
+ def revision(library_path = self.local_path)
+ @revision ||= begin
+ missing_git_repo = !File.exist?(library_path.to_s + "/.git")
+ return if library_path.nil? || missing_git_repo
+ grit = Grit::Repo.new(library_path)
+ grit.commits('master', 1).first.sha
+ end
end
- def to_hash
- { :name => self.name, :revision => revision, :source => self.source }
+ # Returns enhanced to_s string representation
+ def to_s
+ "Library: #{self.name} (#{self.source}) [#{self.revision}]"
end
protected
- def fetch_git(target_path)
- @local_path = File.join(target_path, @name)
+ # Downloads remote library to vendored path from git repo (if needed)
+ # @library_path.fetch_git("/path/to/project/vendored")
+ def fetch_git(vendored_path)
+ @local_path = File.join(vendored_path, @name)
if self.revision.nil? # no local copy
+ FileUtils.mkdir_p(vendored_path)
puts "fetching #{self.name} from #{self.source}"
puts `git clone #{self.source} #{@local_path}`
end
end # fetch_git
- end
-end
+ end # Library
+end # Vendor
View
34 lib/vendor/lock_file.rb
@@ -0,0 +1,34 @@
+# Represents a Vendor.lock file detailing the locked libraries and versions
+
+module Vendor
+ class LockFile
+ include Vendor::Helpers
+
+ # Construct a lockfile representation
+ # Vendor::LockFile.new("/path/to/project/Vendor.lock", <DependencyFile>, ...)
+ def initialize(lock_path, depfile, options={})
+ @path = lock_path
+ @depfile = depfile
+ end
+
+ # Returns libraries specified in Vendor.lock
+ # @lockfile.libraries => [<Library>, <Library>]
+ def libraries
+ File.read(@path).split("\n").map do |file_data|
+ split_data = file_data.split(" | ")
+ lib_data = { :name => split_data.first, :git => split_data[1], :revision => split_data.last }
+ resolve_library(lib_data)
+ end
+ end # locked_libraries
+
+ # Outputs a lock file with specific versions
+ # @lockfile.generate! => ...writes lock file...
+ def generate!
+ f = File.new(@path, 'w')
+ @depfile.libraries.each do |library|
+ f.puts "#{library.name} | #{library.source} | #{library.revision}"
+ end
+ f.close
+ end
+ end # LockFile
+end # Vendor
View
50 lib/vendor/manager.rb
@@ -1,5 +1,55 @@
+# Manager that handles all essential vendoring functionality
+
module Vendor
class Manager
+ # Vendor::Manager.new("/path/to/project", :vendored_path => "path/to/project/vendored")
+ # options = { :vendors_file => "/path/to/project/Vendors" }
+ def initialize(current_path, options={})
+ @folder = current_path
+ @vendored_path = options.delete(:vendored_path) || File.join(@folder, "vendored")
+ @vendors_file_path = options.delete(:vendors_file) || File.join(@folder, "Vendors")
+ @lock_file_path = options.delete(:lock_file) || File.join(@folder, "Vendors.lock")
+ @depfile = DependencyFile.new(@vendors_file_path)
+ @lockfile = LockFile.new(@lock_file_path, @depfile)
+ @xcode_handler = XcodeHandler.new(@folder)
+ end
+
+ # Installs all deps to vendored path and generates a lockfile
+ # @manager.install! => ...vendor to local path and generate lock file...
+ def install!
+ self.vendor!
+ @lockfile.generate!
+ end
+
+ # Returns the libraries required by Vendors file
+ # @manager.required_libraries => [<Library>, ...]
+ def required_libraries
+ @depfile.libraries
+ end
+
+ # Returns libraries that are locked as dependencies in Vendors.lock
+ # @manager.locked_libraries => [<Library>, ...]
+ def locked_libraries
+ @lockfile.libraries
+ end
+
+ # Returns libraries that are missing from local installation
+ # @manager.locked_libraries => [<Library>, ...]
+ def missing_libraries
+ self.locked_libraries.select do |lib|
+ local_path = File.join(@vendored_path, lib.name)
+ installed = @depfile.libraries.find { |l| l.name == lib.name }
+ installed.nil? || installed.revision(local_path) != lib.revision
+ end
+ end # missing_libraries
+
+ protected
+ # Vendors the various libraries to the specified "vendored" path
+ # @manager.vendor!
+ def vendor!
+ @depfile.sources.each { |source| source.fetch }
+ self.required_libraries.each { |library| library.fetch(@vendored_path) }
+ end
end
end
View
6 lib/vendor/source.rb
@@ -1,3 +1,5 @@
+# Represents a source from which fetch and load libraries
+
module Vendor
class Source
attr_reader :path
@@ -8,10 +10,14 @@ def initialize(path)
@path = path
end
+ # Returns enhanced string representation
+ # @source.to_s = "<Source> @path="http://path/to/remote/source/repo.git""
def to_s
"#{super} @path=#{self.path}"
end # to_s
+ # Fetch source and require files locally
+ # @source.fetch
def fetch
if @path =~ /.git$/
puts "[source] fetching source path from #{self.path}"
View
4 lib/vendor/xcode_handler.rb
@@ -1,7 +1,9 @@
+# Manages XCode interactions using AppleScript
+
require 'appscript'
module Vendor
- module XcodeHandler
+ class XcodeHandler
# Vendor::XcodeHandler.new
def initialize(project_path)
@app = Appscript.app('Xcode')
Please sign in to comment.
Something went wrong with that request. Please try again.