Commit 064085ec authored by Fabio Pelosin's avatar Fabio Pelosin

Merge branch 'master' into lookback-pods-by-config

* master: (294 commits)
  Bundle: update cocoapods-core
  Bundle: update Xcodeproj
  Validator: check license only in root spec
  Bundle: udpate cocoapods-core
  Integration: update for Xcodeproj
  Specs: fix for changes to Xcodeproj
  Update integration specs for Xcodeproj
  Gem: update Xcodeproj dependency
  Integration: update acknowledgements
  Bundle: make xcodeproj faster on mac
  Update integration specs for Xcodeproj
  Bundle:update
  CI: disable Ruby 1.8.7 for now
  Xcodeproj: udpate
  Bundle: update cocoapods-trunk version
  [Sandbox] Evaluate podspecs from their original path
  [Install/Update] Clarify command description. Relates to #2270.
  [README] Flatten badges
  [Gemspec] Update to nap 0.8
  Pod::Command::Spec::Lint::description update
  ...

Conflicts:
	CHANGELOG.md
	Gemfile.lock
	spec/cocoapods-integration-specs
parents a009895b c2366c33
......@@ -30,4 +30,14 @@ examples/RelativePathProject/RelativePathProject/RelativePathProject.xcodeproj
coverage/
.coveralls.yml
# IDEs
*.xccheckout
.idea/
# RVM files
/.rvmrc
/.ruby-version
/.ruby-gemset
# Bundler files
/.bundle
[submodule "spec/fixtures/integration/ASIHTTPRequest"]
path = spec/fixtures/integration/ASIHTTPRequest
url = https://github.com/pokeb/asi-http-request.git
[submodule "spec/fixtures/integration/SSZipArchive"]
path = spec/fixtures/integration/SSZipArchive
url = https://github.com/samsoffes/ssziparchive.git
[submodule "spec/fixtures/integration/JSONKit"]
path = spec/fixtures/integration/JSONKit
url = https://github.com/johnezang/JSONKit.git
[submodule "spec/fixtures/integration/sstoolkit"]
path = spec/fixtures/integration/sstoolkit
url = https://github.com/samsoffes/sstoolkit.git
ignore = dirty
[submodule "spec/fixtures/spec-repos/master"]
path = spec/fixtures/spec-repos/master
url = https://github.com/CocoaPods/Specs.git
......
recipe :ruby
Kicker::Recipes::Ruby.runner_bin = 'bacon'
Kicker::Recipes::Ruby.runner_bin = 'bacon --quiet'
process do |files|
specs = files.take_and_map do |file|
......
# Sets Travis to run the Ruby specs on OS X machines which are required to
# build the native extensions of Xcodeproj.
#
language: objective-c
env:
# This is what 10.8.x comes with and we want to support that.
- RVM_RUBY_VERSION=system NOEXEC_DISABLE=1 XCODEPROJ_BUILD=1 BUNDLE_WITHOUT='debugging:documentation' RUBY_VERSION_SPECIFIC='sudo ln -s /usr/bin/llvm-gcc-4.2 /usr/bin/gcc-4.2' SSL_CERT_FILE=/usr/local/share/cacert.pem GIT_AUTHOR_NAME=CocoaPods GIT_AUTHOR_EMAIL=cocoapods@example.com PYTHONPATH=/usr/local/lib/python2.7/site-packages
- RVM_RUBY_VERSION=2.0.0-p247 NOEXEC_DISABLE=1 XCODEPROJ_BUILD=1 BUNDLE_WITHOUT='debugging:documentation' RUBY_VERSION_SPECIFIC='sudo gem install bundler --no-ri --no-rdoc' GIT_AUTHOR_NAME=CocoaPods GIT_AUTHOR_EMAIL=cocoapods@example.com PYTHONPATH=/usr/local/lib/python2.7/site-packages
- RVM_RUBY_VERSION=system
# - RVM_RUBY_VERSION=1.8.7-p358
before_install:
- export LANG=en_US.UTF-8
- curl http://curl.haxx.se/ca/cacert.pem -o /usr/local/share/cacert.pem
# - sh -c 'if [ "$RVM_RUBY_VERSION" != "system" ]; then rvm install $RVM_RUBY_VERSION --without-tcl --without-tk; fi'
- source ~/.rvm/scripts/rvm && rvm use $RVM_RUBY_VERSION
- brew update && brew install bzr
install: eval $RUBY_VERSION_SPECIFIC && rake bootstrap[use_bundle_dir]
script: bundle exec rake spec:ci
- source ~/.rvm/scripts/rvm
- if [[ $RVM_RUBY_VERSION != 'system' ]]; then rvm install $RVM_RUBY_VERSION; fi
- rvm use $RVM_RUBY_VERSION
- if [[ $RVM_RUBY_VERSION == 'system' ]]; then export ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future; fi
- if [[ $RVM_RUBY_VERSION == 'system' ]]; then sudo gem install bundler --no-ri --no-rdoc; else gem install bundler --no-ri --no-rdoc; fi
install:
- bundle install --without=debugging documentation --path ./travis_bundle_dir
# CocoaPods/CocoaPods specific
- ./bin/pod repo update --silent
script: rake spec
notifications:
campfire:
on_success: change
on_failure: always
rooms:
- secure: "qOE5zmgaHe/qQu3W9rmj7wygA5Ivl+cx50fqWGag2bdRl8ly5yj1NVoOKk/O\nZmQc4Lze+301uvTXi+r5v8A/tF6W1kUZw7yBiKuXoYFUGmDiVR9o2I/FPwkL\ngSzPJttrXTQfkQ4PbnrkX+JO+5bLWrKaO0hKXT4B2yUu4UXLVk0="
......@@ -4,14 +4,392 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides
## Master
###### Bug Fixes
* Include configurations a user explicitly specifies in their Podfile when the
`--no-integrate` option is specified.
[Eloy Durán](https://github.com/alloy)
* Properly quote the `-isystem` values in the xcconfig files.
[Eloy Durán](https://github.com/alloy)
* Include configurations a user explicitely specifies in their Podfile when the
`--no-integrate` option is specified.
##### Bug Fixes
* Fixed pod repo push to first check if Specs directory exists and if so push there.
[Edward Valentini](edwardvalentini)
[#2060](https://github.com/CocoaPods/CocoaPods/issues/2060)
* Fixed `pod outdated` to not include subspecs.
[Ash Furrow](ashfurrow]
[#2136](https://github.com/CocoaPods/CocoaPods/issues/2136)
* Always evaluate podspecs from the original podspec directory. This fixes
issues when you are using relative paths inside ruby podspecs and using a
pod's via `:path`.
[Kyle Fuller](kylef)
[pod-template#50](https://github.com/CocoaPods/pod-template/issues/50)
* Fixed spec linting to not warn for missing license file in subspecs.
[Fabio Pelosin][irrationalfab]
[Core#132](https://github.com/CocoaPods/Core/issues/132)
## 0.33.1
##### Bug Fixes
* Fix `pod spec lint` for `json` podspecs.
[Fabio Pelosin][irrationalfab]
[#2157](https://github.com/CocoaPods/CocoaPods/issues/2157)
* Fixed downloader issues related to `json` podspecs.
[Fabio Pelosin][irrationalfab]
[#2158](https://github.com/CocoaPods/CocoaPods/issues/2158)
* Fixed `--no-ansi` flag in help banners.
[Fabio Pelosin][irrationalfab]
[#34](https://github.com/CocoaPods/CLAide/issues/34)
## 0.33.0
##### Breaking
* The deprecated `pre_install` and the `pod_install` hooks of the specification
class have been removed.
[Fabio Pelosin][irrationalfab]
[#2151](https://github.com/CocoaPods/CocoaPods/issues/2151)
[#2153](https://github.com/CocoaPods/CocoaPods/pull/2153)
##### Enhancements
* Added the `cocoapods-trunk` plugin which introduces the `trunk` subcommand.
[Fabio Pelosin][irrationalfab]
[#2151](https://github.com/CocoaPods/CocoaPods/issues/2151)
[#2153](https://github.com/CocoaPods/CocoaPods/pull/2153)
* The `pod push` sub-command has been moved to the `pod repo push` sub-command.
Moreover pushing to the master repo from it has been disabled.
[Fabio Pelosin][irrationalfab]
[#2151](https://github.com/CocoaPods/CocoaPods/issues/2151)
[#2153](https://github.com/CocoaPods/CocoaPods/pull/2153)
* Overhauled command line interface. Add support for auto-completion script
(d). If auto-completion is enabled for your shell you can configure it for
CocoaPods with the following command:
rm -f /usr/local/share/zsh/site-functions/_pod
dpod --completion-script > /usr/local/share/zsh/site-functions/_pod
exec zsh
Currently only the Z shell is supported.
[Fabio Pelosin][irrationalfab]
[CLAide#25](https://github.com/CocoaPods/CLAide/issues/25)
[CLAide#20](https://github.com/CocoaPods/CLAide/issues/20)
[CLAide#19](https://github.com/CocoaPods/CLAide/issues/19)
[CLAide#17](https://github.com/CocoaPods/CLAide/issues/17)
[CLAide#12](https://github.com/CocoaPods/CLAide/issues/12)
* The `--version` flag is now only supported for the root `pod` command. If
used in conjunction with the `--verbose` flag the version of the detected
plugins will be printed as well.
[Fabio Pelosin][irrationalfab]
[CLAide#13](https://github.com/CocoaPods/CLAide/issues/13)
[CLAide#14](https://github.com/CocoaPods/CLAide/issues/14)
* The extremely meta `cocoaPods-plugins` is now installed by default providing
information about the available and the installed plug-ins.
[David Grandinetti](https://github.com/dbgrandi)
[Olivier Halligon](https://github.com/AliSoftware)
[Fabio Pelosin][irrationalfab]
[#2092](https://github.com/CocoaPods/CocoaPods/issues/2092)
* Validate the reachability of `social_media_url`, `documentation_url` and
`docset_url` in podspecs we while linting a specification.
[Kyle Fuller](https://github.com/kylef)
[#2025](https://github.com/CocoaPods/CocoaPods/issues/2025)
* Print the current version when the repo/lockfile requires a higher version.
[Samuel E. Giddins](https://github.com/segiddins)
[#2049](https://github.com/CocoaPods/CocoaPods/issues/2049)
* Show `help` when running the `pod` command instead of defaulting to `pod
install`.
[Kyle Fuller](https://github.com/kylef)
[#1771](https://github.com/CocoaPods/CocoaPods/issues/1771)
##### Bug Fixes
* Show the actual executable when external commands fail.
[Boris Bügling][neonichu]
[#2102](https://github.com/CocoaPods/CocoaPods/issues/2102)
* Fixed support for file references in the workspace generated by CocoaPods.
[Kyle Fuller][kylef]
[Fabio Pelosin][irrationalfab]
[Xcodeproj#105](https://github.com/CocoaPods/Xcodeproj/pull/150)
* Show a helpful error message when reading version information with merge
conflict.
[Samuel E. Giddins][segiddins]
[#1853](https://github.com/CocoaPods/CocoaPods/issues/1853)
* Show deprecated specs when invoking `pod outdated`.
[Samuel E. Giddins](https://github.com/segiddins)
[#2003](https://github.com/CocoaPods/CocoaPods/issues/2003)
* Fixes an issue where `pod repo update` may start an un-committed merge.
[Kyle Fuller][kylef]
[#2024](https://github.com/CocoaPods/CocoaPods/issues/2024)
## 0.32.1
##### Bug Fixes
* Fixed the Podfile `default_subspec` attribute in nested subspecs.
[Fabio Pelosin][irrationalfab]
[#2050](https://github.com/CocoaPods/CocoaPods/issues/2050)
## 0.32.0
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/master...0.31.1)
[CocoaPods-Core](https://github.com/CocoaPods/Core/compare/master...0.31.1)
##### Enhancements
* Allow to update only a list of given pods with `pod update [POD_NAMES...]`.
[Marius Rackwitz](https://github.com/mrackwitz)
[CocoaPods#760](https://github.com/CocoaPods/CocoaPods/issues/760)
* `pod update` prints the previous version of the updated pods.
[Andrea Mazzini](https://github.com/andreamazz)
[#2008](https://github.com/CocoaPods/CocoaPods/issues/2008)
* `pod update` falls back to `pod install` if no Lockfile is present.
[Marius Rackwitz](https://github.com/mrackwitz)
* File references in the Pods project for development Pods now are absolute if
the dependency is specified with an absolute paths.
[Samuel Ford](https://github.com/samuelwford)
[#1042](https://github.com/CocoaPods/CocoaPods/issues/1042)
* Added `deprecated` and `deprecated_in_favor_of` attributes to Specification
DSL.
[Paul Young](https://github.com/paulyoung)
[Core#87](https://github.com/CocoaPods/Core/pull/87)
* Numerous improvements to the validator and to the linter.
* Validate the reachability of screenshot URLs in podspecs while linting a
specification.
[Kyle Fuller](https://github.com/kylef)
[#2010](https://github.com/CocoaPods/CocoaPods/issues/2010)
* Support HTTP redirects when linting homepage and screenshots.
[Boris Bügling](https://github.com/neonichu)
[#2027](https://github.com/CocoaPods/CocoaPods/pull/2027)
* The linter now checks `framework` and `library` attributes for invalid
strings.
[Paul Williamson](https://github.com/squarefrog)
[Fabio Pelosin](irrationalfab)
[Core#66](https://github.com/CocoaPods/Core/issues/66)
[Core#96](https://github.com/CocoaPods/Core/pull/96)
[Core#105](https://github.com/CocoaPods/Core/issues/105)
* The Linter will not check for comments anymore.
[Fabio Pelosin][irrationalfab]
[Core#108](https://github.com/CocoaPods/Core/issues/108)
* Removed legacy checks from the linter.
[Fabio Pelosin][irrationalfab]
[Core#108](https://github.com/CocoaPods/Core/issues/108)
* Added logic to handle subspecs and platform scopes to linter check of
the `requries_arc` attribute.
[Fabio Pelosin][irrationalfab]
[CocoaPods#2005](https://github.com/CocoaPods/CocoaPods/issues/2005)
* The linter no longer considers empty a Specification if it only specifies the
`resource_bundle` attribute.
[Joshua Kalpin][Kapin]
[#63](https://github.com/CocoaPods/Core/issues/63)
[#95](https://github.com/CocoaPods/Core/pull/95)
* `pod lib create` is now using the `configure` file instead of the
`_CONFIGURE.rb` file.
[Piet Brauer](https://github.com/pietbrauer)
[Orta Therox](https://github.com/orta)
* `pod lib create` now disallows any pod name that begins with a `.`
[Dustin Clark](https://github.com/clarkda)
[#2026](https://github.com/CocoaPods/CocoaPods/pull/2026)
[Core#97](https://github.com/CocoaPods/Core/pull/97)
[Core#98](https://github.com/CocoaPods/Core/issues/98)
* Prevent the user from using `pod` commands as root.
[Kyle Fuller](https://github.com/kylef)
[#1815](https://github.com/CocoaPods/CocoaPods/issues/1815)
* Dependencies declared with external sources now support HTTP downloads and
have improved support for all the options supported by the downloader.
[Fabio Pelosin][irrationalfab]
* An informative error message is presented when merge conflict is detected in
a YAML file.
[Luis de la Rosa](https://github.com/luisdelarosa)
[#69](https://github.com/CocoaPods/Core/issues/69)
[#100](https://github.com/CocoaPods/Core/pull/100)
##### Bug Fixes
* Fixed the Podfile `default_subspec` attribute in nested subspecs.
[Fabio Pelosin][irrationalfab]
[#1021](https://github.com/CocoaPods/CocoaPods/issues/1021)
* Warn when including deprecated pods
[Samuel E. Giddins](https://github.com/segiddins)
[#2003](https://github.com/CocoaPods/CocoaPods/issues/2003)
## 0.31.1
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.31.1...0.31.0)
[CocoaPods-Core](https://github.com/CocoaPods/Core/compare/0.31.1...0.31.0)
##### Minor Enhancements
* The specification now strips the indentation of the `prefix_header` and
`prepare_command` to aide their declaration as a here document (similarly to
what it already does with the description).
[Fabio Pelosin][irrationalfab]
[Core#51](https://github.com/CocoaPods/Core/issues/51)
##### Bug Fixes
* Fix linting for Pods which declare a private repo as the source.
[Boris Bügling](https://github.com/neonichu)
[Core#82](https://github.com/CocoaPods/Core/issues/82)
## 0.31.0
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.30.0...0.31.0)
[CocoaPods-Core](https://github.com/CocoaPods/Core/compare/0.30.0...0.31.0)
##### Enhancements
* Warnings are not promoted to errors anymore to maximise compatibility with
existing libraries.
[Fabio Pelosin](https://github.com/irrationalfab)
[#1629](https://github.com/CocoaPods/CocoaPods/issues/1629)
* Include the versions of the Pods to the output of `pod list`.
[Stefan Damm](https://github.com/StefanDamm)
[Robert Zuber](https://github.com/z00b)
[#1617](https://github.com/CocoaPods/CocoaPods/issues/1617)
* Generated prefix header file will now have unique prefix_header_contents for
Pods with subspecs.
[Luis de la Rosa](https://github.com/luisdelarosa)
[#1449](https://github.com/CocoaPods/CocoaPods/issues/1449)
* The linter will now check the reachability of the homepage of Podspecs during
a full lint.
[Richard Lee](https://github.com/dlackty)
[Fabio Pelosin](https://github.com/irrationalfab)
[#1704](https://github.com/CocoaPods/CocoaPods/issues/1704)
[Core#70](https://github.com/CocoaPods/Core/pull/70)
* Improved detection of the last version of a specification in `pod spec`
subcommands.
[Laurent Sansonetti](https://github.com/lrz)
[#1953](https://github.com/CocoaPods/CocoaPods/pull/1953)
* Display advised settings for Travis CI in the warning related presented when
the terminal encoding is not set to UTF-8.
[Richard Lee](https://github.com/dlackty)
[#1933](https://github.com/CocoaPods/CocoaPods/issues/1933)
[#1941](https://github.com/CocoaPods/CocoaPods/pull/1941)
* Unset the `CDPATH` env variable before shelling-out to `prepare_command`.
[Marc Boquet](https://github.com/apalancat)
[#1943](https://github.com/CocoaPods/CocoaPods/pull/1943)
##### Bug Fixes
* Resolve crash related to the I18n deprecation warning.
[Eloy Durán](https://github.com/alloy)
[#1950](https://github.com/CocoaPods/CocoaPods/issues/1950)
* Fix compilation issues related to the native Extension of Xcodeproj.
[Eloy Durán](https://github.com/alloy)
* Robustness against user Git configuration and against merge commits in `pod
repo` subcommands.
[Boris Bügling](https://github.com/neonichu)
[#1949](https://github.com/CocoaPods/CocoaPods/issues/1949)
[#1978](https://github.com/CocoaPods/CocoaPods/pull/1978)
* Gracefully inform the user if the `:head` option is not supported for a given
download strategy.
[Boris Bügling](https://github.com/neonichu)
[#1947](https://github.com/CocoaPods/CocoaPods/issues/1947)
[#1958](https://github.com/CocoaPods/CocoaPods/pull/1958)
* Cleanup a pod directory if error occurs while downloading.
[Alex Rothenberg](https://github.com/alexrothenberg)
[#1842](https://github.com/CocoaPods/CocoaPods/issues/1842)
[#1960](https://github.com/CocoaPods/CocoaPods/pull/1960)
* No longer warn for Github repositories with OAuth authentication.
[Boris Bügling](https://github.com/neonichu)
[#1928](https://github.com/CocoaPods/CocoaPods/issues/1928)
[Core#77](https://github.com/CocoaPods/Core/pull/77)
* Fix for when using `s.version` as the `:tag` for a git repository in a
Podspec.
[Joel Parsons](https://github.com/joelparsons)
[#1721](https://github.com/CocoaPods/CocoaPods/issues/1721)
[Core#72](https://github.com/CocoaPods/Core/pull/72)
* Improved escaping of paths in Git downloader.
[Vladimir Burdukov](https://github.com/chipp)
[cocoapods-downloader#14](https://github.com/CocoaPods/cocoapods-downloader/pull/14)
* Podspec without explicitly set `requires_arc` attribute no longer passes the
lint.
[Richard Lee](https://github.com/dlackty)
[#1840](https://github.com/CocoaPods/CocoaPods/issues/1840)
[Core#71](https://github.com/CocoaPods/Core/pull/71)
* Properly quote headers in the `-isystem` compiler flag of the aggregate
targets.
[Eloy Durán](https://github.com/alloy)
[#1862](https://github.com/CocoaPods/CocoaPods/issues/1862)
[#1894](https://github.com/CocoaPods/CocoaPods/pull/1894)
## 0.30.0
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.29.0...0.30.0)
###### Enhancements
* Radically reduce first run pod setup bandwidth by creating a shallow clone of
the ‘master’ repo by default. Use the `--no-shallow` option to perform a full
clone instead.
[Jeff Verkoeyen](https://github.com/jverkoey)
[#1803](https://github.com/CocoaPods/CocoaPods/pull/1803)
* Improves the error message when searching with an invalid regular expression.
[Kyle Fuller](https://github.com/kylef)
* Improves `pod init` to save Xcode project file in Podfile when one was supplied.
[Kyle Fuller](https://github.com/kylef)
* Adds functionality to specify a template URL for the `pod lib create` command.
[Piet Brauer](https://github.com/pietbrauer)
###### Bug Fixes
* Fixes a bug with `pod repo remove` silently handling permission errors.
[Kyle Fuller](https://github.com/kylef)
[#1778](https://github.com/CocoaPods/CocoaPods/issues/1778)
* `pod push` now properly checks that the repo has changed before attempting
to commit. This only affected pods with special characters (such as `+`) in
their names.
[Gordon Fontenot](https://github.com/gfontenot)
[#1739](https://github.com/CocoaPods/CocoaPods/pull/1739)
## 0.29.0
......@@ -2075,3 +2453,8 @@ allowing you to automate Xcode related tasks.
[5]: https://github.com/tomaz/appledoc
[6]: https://github.com/CocoaPods/CocoaPods/compare/0.5.1...0.6.0
[7]: https://github.com/CocoaPods/CocoaPods/compare/0.3.10...0.5.0
[irrationalfab]: https://github.com/irrationalfab
[kylef]: (https://github.com/kylef)
[neonichu]: (https://github.com/neonichu)
# Do’s and Don’ts
* **Search the solutions in the [troubleshooting guide](http://guides.cocoapods.org/using/troubleshooting.html).** Or any of the many other [guides](http://guides.cocoapods.org).
* **Search tickets before you file a new one.** Add to tickets if you have new information about the issue.
* **Only file tickets about the CocoaPods tool itself.** This includes [CocoaPods](https://github.com/CocoaPods/CocoaPods/issues),
[CocoaPods/Core](https://github.com/CocoaPods/Core/issues), and [Xcodeproj](https://github.com/CocoaPods/Xcodeproj/issues).
......@@ -48,7 +49,7 @@ Should you require a feature isn't suited for mainstream users, consider suggest
## Pull Requests
We **love** pull requests and if a contribution is significant we tend to offer
push access.
push access. We suggest you take a look at our [Contributing guide](http://guides.cocoapods.org/contributing/contribute-to-cocoapods.html) for info on development setup, and some of our best practices.
All contributions _will_ be licenced under the MIT license.
......
......@@ -10,31 +10,41 @@ group :development do
# For more info see http://bundler.io/git.html#local
gem 'cocoapods-core', :git => "https://github.com/CocoaPods/Core.git", :branch => 'lookback-pods-by-config'
gem 'xcodeproj', :git => "https://github.com/CocoaPods/Xcodeproj.git", :branch => 'master'
gem 'cocoapods-downloader', :git => "https://github.com/CocoaPods/cocoapods-downloader.git", :branch => 'master'
gem 'claide', :git => 'https://github.com/CocoaPods/CLAide.git', :branch => 'master'
gem 'cocoapods-downloader', :git => "https://github.com/CocoaPods/cocoapods-downloader.git", :branch => 'master'
gem 'cocoapods-try', :git => 'https://github.com/CocoaPods/cocoapods-try.git', :branch => 'master'
gem 'cocoapods-plugins', :git => 'https://github.com/CocoaPods/cocoapods-plugins.git', :branch => 'master'
gem 'cocoapods-trunk', :git => 'https://github.com/CocoaPods/cocoapods-trunk.git', :branch => 'master'
gem "mocha"
gem 'rake', '~> 10.1.0' # Ruby 1.8.7
gem "mocha", '~> 1.0.0' # Issues with Ruby 2.0.0 on Travis
gem "bacon"
gem "mocha-on-bacon"
gem 'prettybacon', :git => 'https://github.com/irrationalfab/PrettyBacon.git', :branch => 'master'
gem "rake"
gem 'prettybacon'
gem 'webmock', "< 1.16"
# For the integration tests
gem "diffy"
# Lock the current lowest requirement for ActiveSupport 3 to ensure we don't
# re-introduce https://github.com/CocoaPods/CocoaPods/issues/1950
gem 'i18n', '0.6.4'
gem 'mime-types', '< 2' # v2 is 1.9.x only
gem 'coveralls', :require => false
# Explicitly add this, otherwise it might sometimes be missing:
# https://github.com/lemurheavy/coveralls-ruby/blob/master/coveralls-ruby.gemspec#L23.
gem 'simplecov'
if RUBY_PLATFORM.include?('darwin')
# Make Xcodeproj faster
gem 'libxml-ruby'
end
end
group :debugging do
# Only while we test the trunk app.
gem 'cocoapods-trunk', :git => "https://github.com/alloy/cocoapods-trunk.git"
gem "rb-fsevent"
gem "kicker", :git => "https://github.com/alloy/kicker.git", :branch => "master"
gem "kicker"
gem "awesome_print"
gem "pry"
# The released gem leads to stack too deep when profiling a full run.
......
GIT
remote: https://github.com/CocoaPods/CLAide.git
revision: f5e4752d8cc4ba055e1d96713275e9955fea9f37
revision: 2d1ade5e062be937e630920c7399dbe1bee48d93
branch: master
specs:
claide (0.4.0)
claide (0.6.1)
GIT
remote: https://github.com/CocoaPods/Core.git
revision: 6d775a30b10246ee0f87dc241788ab0b5fe89447
revision: 1f6273aeb346b9d21008438b37594106fca4b7f6
branch: lookback-pods-by-config
specs:
cocoapods-core (0.29.0)
activesupport (>= 3.2.15, < 4)
cocoapods-core (0.33.1)
activesupport (>= 3.2.15)
fuzzy_match (~> 2.0.4)
json_pure (~> 1.8)
nap (~> 0.5)
GIT
remote: https://github.com/CocoaPods/Xcodeproj.git
revision: 0704b7772370feb8be154ace0ce48e09f215aeaf
revision: f835e6e1145812ac04ac4b658321c727c2967547
branch: master
specs:
xcodeproj (0.14.1)
xcodeproj (0.18.0)
CFPropertyList (~> 2.2)
activesupport (~> 3.0)
colored (~> 1.2)
rake
GIT
remote: https://github.com/CocoaPods/cocoapods-downloader.git
revision: 4a95877b20893b374dfd43624e12bac167feef05
revision: 27a5c58d7d7aaf8886c47624260d167fa776175c
branch: master
specs:
cocoapods-downloader (0.3.0)
cocoapods-downloader (0.6.1)
GIT
remote: https://github.com/alloy/cocoapods-trunk.git
revision: 20b9a8bb60ad6e59df4df7d4a960a4dd4a41afa0
remote: https://github.com/CocoaPods/cocoapods-plugins.git
revision: 0740e01bc8b99cbd8249e766fc4a87eae71e995e
branch: master
specs:
cocoapods-trunk (0.0.1)
json (~> 1.8)
nap (>= 0.6)
netrc
cocoapods-plugins (0.2.0)
nap
GIT
remote: https://github.com/alloy/kicker.git
revision: 87b0047202c0320d4ef62e1f1a4b2cbdefadf008
remote: https://github.com/CocoaPods/cocoapods-trunk.git
revision: c62f86f83bf77faf8baf80359cc511dd1014fcfb
branch: master
specs:
kicker (3.0.0)
listen (~> 1.3.0)
notify (~> 0.5.2)
cocoapods-trunk (0.1.4)
json_pure (~> 1.8)
nap (>= 0.6)
netrc
GIT
remote: https://github.com/irrationalfab/PrettyBacon.git
revision: eaf7e6c786fd5ccc6fb88e943bf7c5e6c27569a3
remote: https://github.com/CocoaPods/cocoapods-try.git
revision: 754e53f3c3eec4c5ba129d6955484fb27631d1d5
branch: master
specs:
prettybacon (0.0.1)
bacon (~> 1.2)
cocoapods-try (0.3.0)
GIT
remote: https://github.com/ruby-prof/ruby-prof.git
revision: b56c1268ba001f5eb55f940ca1c83bc6b83a9752
revision: e3317c4bf0b58dceee86e5dd9cf03165fcfd964f
specs:
ruby-prof (0.14.2)
ruby-prof (0.15.1)
PATH
remote: .
specs:
cocoapods (0.29.0)
cocoapods (0.33.1)
activesupport (>= 3.2.15, < 4)
claide (~> 0.4.0)
cocoapods-core (= 0.29.0)
cocoapods-downloader (~> 0.3.0)
cocoapods-try-release-fix (~> 0.1.1)
claide (~> 0.6.1)
cocoapods-core (= 0.33.1)
cocoapods-downloader (~> 0.6.1)
cocoapods-plugins (~> 0.2.0)
cocoapods-trunk (~> 0.1.4)
cocoapods-try (~> 0.3.0)
colored (~> 1.2)
escape (~> 0.0.4)
json_pure (~> 1.8)
nap (~> 0.5)
nap (~> 0.8)
open4 (~> 1.3)
xcodeproj (~> 0.14.1)
xcodeproj (~> 0.18.0)
GEM
remote: http://rubygems.org/
specs:
activesupport (3.2.16)
CFPropertyList (2.2.8)
activesupport (3.2.19)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
addressable (2.3.6)
awesome_print (1.2.0)
bacon (1.2.0)
cocoapods-try-release-fix (0.1.1)
coderay (1.1.0)
colored (1.2)
coveralls (0.7.0)
......@@ -98,60 +100,73 @@ GEM
simplecov (>= 0.7)
term-ansicolor
thor
diffy (3.0.1)
docile (1.1.3)
crack (0.4.2)
safe_yaml (~> 1.0.0)
diffy (3.0.6)
docile (1.1.5)
escape (0.0.4)
ffi (1.9.3)
fuzzy_match (2.0.4)
github-markup (1.0.1)
i18n (0.6.9)
json (1.8.1)
github-markup (1.2.1)
posix-spawn (~> 0.3.8)
i18n (0.6.4)
json_pure (1.8.1)
kicker (3.0.0)
listen (~> 1.3.0)
notify (~> 0.5.2)
libxml-ruby (2.7.0)
listen (1.3.1)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
rb-kqueue (>= 0.2)
metaclass (0.0.2)
metaclass (0.0.4)
method_source (0.8.2)
mime-types (1.25.1)
mocha (1.0.0)
metaclass (~> 0.0.1)
mocha-on-bacon (0.2.2)
mocha (>= 0.13.0)
multi_json (1.8.4)
nap (0.6.0)
multi_json (1.10.1)
nap (0.8.0)
netrc (0.7.7)
notify (0.5.2)
open4 (1.3.0)
open4 (1.3.4)
posix-spawn (0.3.8)
pry (0.9.12.6)
coderay (~> 1.0)
method_source (~> 0.8)
prettybacon (0.0.2)
bacon (~> 1.2)
pry (0.10.0)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pygments.rb (0.5.4)
pygments.rb (0.6.0)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
rake (10.1.1)
rb-fsevent (0.9.4)
rb-inotify (0.9.3)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
rb-kqueue (0.2.0)
rb-kqueue (0.2.3)
ffi (>= 0.5.0)
redcarpet (2.3.0)
rest-client (1.6.7)
mime-types (>= 1.16)
simplecov (0.8.2)
rest-client (1.7.2)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
safe_yaml (1.0.3)
simplecov (0.9.0)
docile (~> 1.1.0)
multi_json
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
slop (3.4.7)
term-ansicolor (1.2.2)
tins (~> 0.8)
thor (0.18.1)
tins (0.13.2)
slop (3.6.0)
term-ansicolor (1.3.0)
tins (~> 1.0)
thor (0.19.1)
tins (1.3.0)
webmock (1.15.2)
addressable (>= 2.2.7)
crack (>= 0.3.2)
yajl-ruby (1.1.0)
yard (0.8.7.3)
yard (0.8.7.4)
PLATFORMS
ruby
......@@ -163,21 +178,26 @@ DEPENDENCIES
cocoapods!
cocoapods-core!
cocoapods-downloader!
cocoapods-plugins!
cocoapods-trunk!
cocoapods-try!
coveralls
diffy
github-markup
kicker!
i18n (= 0.6.4)
kicker
libxml-ruby
mime-types (< 2)
mocha
mocha (~> 1.0.0)
mocha-on-bacon
prettybacon!
prettybacon
pry
pygments.rb
rake
rake (~> 10.1.0)
rb-fsevent
redcarpet (< 3.0.0)
ruby-prof!
simplecov
webmock (< 1.16)
xcodeproj!
yard
......@@ -2,9 +2,9 @@
### CocoaPods: The Objective-C dependency manager
[![Build Status](http://img.shields.io/travis/CocoaPods/CocoaPods/master.svg)](https://travis-ci.org/CocoaPods/CocoaPods)
[![Gem Version](http://img.shields.io/gem/v/cocoapods.svg)](http://badge.fury.io/rb/cocoapods)
[![Code Climate](http://img.shields.io/codeclimate/github/CocoaPods/CocoaPods.svg)](https://codeclimate.com/github/CocoaPods/CocoaPods)
[![Build Status](http://img.shields.io/travis/CocoaPods/CocoaPods/master.svg?style=flat)](https://travis-ci.org/CocoaPods/CocoaPods)
[![Gem Version](http://img.shields.io/gem/v/cocoapods.svg?style=flat)](http://badge.fury.io/rb/cocoapods)
[![Code Climate](http://img.shields.io/codeclimate/github/CocoaPods/CocoaPods.svg?style=flat)](https://codeclimate.com/github/CocoaPods/CocoaPods)
CocoaPods manages dependencies for your Xcode projects.
......@@ -50,10 +50,10 @@ CocoaPods is composed by the following projects:
| Status | Project | Description | Info |
| :----- | :------ | :--- | :--- |
| [![Build Status](http://img.shields.io/travis/CocoaPods/CocoaPods/master.svg)](http://travis-ci.org/CocoaPods/CocoaPods) | [CocoaPods](https://github.com/CocoaPods/CocoaPods) | The CocoaPods command line tool. | [docs](http://docs.cocoapods.org/cocoapods)
| [![Build Status](http://img.shields.io/travis/CocoaPods/Core/master.svg)](http://travis-ci.org/CocoaPods/Core) | [CocoaPods Core](https://github.com/CocoaPods/Core) | Support for working with specifications and podfiles. | [docs](http://docs.cocoapods.org/cocoapods_core)
| [![Build Status](http://img.shields.io/travis/CocoaPods/cocoapods-downloader/master.svg)](http://travis-ci.org/CocoaPods/cocoapods-downloader) |[CocoaPods Downloader](https://github.com/CocoaPods/cocoapods-downloader) | Downloaders for various source types. | [docs](http://docs.cocoapods.org/cocoapods_downloader/index.html)
| [![Build Status](http://img.shields.io/travis/CocoaPods/Xcodeproj/master.svg)](https://travis-ci.org/CocoaPods/Xcodeproj) | [Xcodeproj](https://github.com/CocoaPods/Xcodeproj) | Create and modify Xcode projects from Ruby. | [docs](http://docs.cocoapods.org/xcodeproj/index.html)
| [![Build Status](http://img.shields.io/travis/CocoaPods/CLAide/master.svg)](https://travis-ci.org/CocoaPods/CLAide) | [CLAide](https://github.com/CocoaPods/CLAide) | A small command-line interface framework. | [docs](http://docs.cocoapods.org/claide/index.html)
| [![Build Status](http://img.shields.io/travis/CocoaPods/Specs/master.svg)](http://travis-ci.org/CocoaPods/Specs) | [Master Repo ](https://github.com/CocoaPods/Specs) | Master repository of specifications. | [guide](http://docs.cocoapods.org/guides/contributing_to_the_master_repo.html)
| [![Build Status](http://img.shields.io/travis/CocoaPods/CocoaPods/master.svg?style=flat)](http://travis-ci.org/CocoaPods/CocoaPods) | [CocoaPods](https://github.com/CocoaPods/CocoaPods) | The CocoaPods command line tool. | [docs](http://docs.cocoapods.org/cocoapods)
| [![Build Status](http://img.shields.io/travis/CocoaPods/Core/master.svg?style=flat)](http://travis-ci.org/CocoaPods/Core) | [CocoaPods Core](https://github.com/CocoaPods/Core) | Support for working with specifications and podfiles. | [docs](http://docs.cocoapods.org/cocoapods_core)
| [![Build Status](http://img.shields.io/travis/CocoaPods/cocoapods-downloader/master.svg?style=flat)](http://travis-ci.org/CocoaPods/cocoapods-downloader) |[CocoaPods Downloader](https://github.com/CocoaPods/cocoapods-downloader) | Downloaders for various source types. | [docs](http://docs.cocoapods.org/cocoapods_downloader/index.html)
| [![Build Status](http://img.shields.io/travis/CocoaPods/Xcodeproj/master.svg?style=flat)](https://travis-ci.org/CocoaPods/Xcodeproj) | [Xcodeproj](https://github.com/CocoaPods/Xcodeproj) | Create and modify Xcode projects from Ruby. | [docs](http://docs.cocoapods.org/xcodeproj/index.html)
| [![Build Status](http://img.shields.io/travis/CocoaPods/CLAide/master.svg?style=flat)](https://travis-ci.org/CocoaPods/CLAide) | [CLAide](https://github.com/CocoaPods/CLAide) | A small command-line interface framework. | [docs](http://docs.cocoapods.org/claide/index.html)
| | [Master Repo ](https://github.com/CocoaPods/Specs) | Master repository of specifications. | [guide](http://docs.cocoapods.org/guides/contributing_to_the_master_repo.html)
def execute_command(command)
if ENV['VERBOSE']
sh(command)
else
output = `#{command} 2>&1`
raise output unless $?.success?
end
end
# Bootstrap task
#-----------------------------------------------------------------------------#
namespace :gem do
def gem_version
require File.expand_path('../lib/cocoapods/gem_version.rb', __FILE__)
Pod::VERSION
end
def gem_filename
"cocoapods-#{gem_version}.gem"
end
#--------------------------------------#
desc "Build a gem for the current version"
task :build do
sh "gem build cocoapods.gemspec"
end
#--------------------------------------#
desc "Install a gem version of the current code"
task :install => :build do
sh "gem install #{gem_filename}"
end
#--------------------------------------#
def silent_sh(command)
output = `#{command} 2>&1`
unless $?.success?
puts output
exit 1
end
output
end
desc "Run all specs, build and install gem, commit version change, tag version change, and push everything"
task :release do
unless ENV['SKIP_CHECKS']
if `git symbolic-ref HEAD 2>/dev/null`.strip.split('/').last != 'master'
$stderr.puts "[!] You need to be on the `master' branch in order to be able to do a release."
exit 1
end
if `git tag`.strip.split("\n").include?(gem_version)
$stderr.puts "[!] A tag for version `#{gem_version}' already exists. Change the version in lib/cocoapods/gem_version.rb"
silent_sh "open lib/cocoapods/gem_version.rb"
exit 1
end
diff_lines = `git diff --name-only`.strip.split("\n")
diff_lines.delete('CHANGELOG.md')
diff_lines.delete('Gemfile.lock')
desc "Initializes your working copy to run the specs"
task :bootstrap, :use_bundle_dir? do |t, args|
title "Environment bootstrap"
if diff_lines.size == 0
$stderr.puts "[!] Change the version number yourself in lib/cocoapods/gem_version.rb"
exit 1
end
puts "Updating submodules"
execute_command "git submodule update --init --recursive"
if diff_lines != ['lib/cocoapods/gem_version.rb']
$stderr.puts "[!] Only change the version number in a release commit!"
exit 1
require 'rbconfig'
if RbConfig::CONFIG['prefix'] == '/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr'
# Workaround Apple's mess. See https://github.com/CocoaPods/Xcodeproj/issues/137
#
# TODO This is not as correct as actually fixing the issue, figure out if we
# can override these build flags:
#
# ENV['DLDFLAGS'] = '-undefined dynamic_lookup -multiply_defined suppress'
ENV['ARCHFLAGS'] = '-Wno-error=unused-command-line-argument-hard-error-in-future'
end
puts "You are about to release `#{gem_version}', is that correct? [y/n]"
exit if $stdin.gets.strip.downcase != 'y'
if system('which bundle')
puts "Installing gems"
if args[:use_bundle_dir?]
execute_command "env XCODEPROJ_BUILD=1 bundle install --path ./travis_bundle_dir"
else
execute_command "env XCODEPROJ_BUILD=1 bundle install"
end
require 'date'
# First check if the required gems have been pushed
gem_spec = eval(File.read(File.expand_path('../cocoapods.gemspec', __FILE__)))
gem_names = ['xcodeproj', 'cocoapods-core', 'cocoapods-downloader', 'claide']
gem_names.each do |gem_name|
gem = gem_spec.dependencies.find { |d| d.name == gem_name }
required_version = gem.requirement.requirements.first.last.to_s
puts "* Checking if #{gem_name} #{required_version} exists on the gem host"
search_result = silent_sh("gem search --all --pre --remote #{gem_name}")
remote_versions = search_result.match(/#{gem_name} \((.*)\)/m)[1].split(', ')
unless remote_versions.include?(required_version)
$stderr.puts "[!] The #{gem_name} version `#{required_version}' required by " \
"this version of CocoaPods does not exist on the gem host. " \
"Either push that first, or fix the version requirement."
else
$stderr.puts "\033[0;31m" \
"[!] Please install the bundler gem manually:\n" \
' $ [sudo] gem install bundler' \
"\e[0m"
exit 1
end
end
# Ensure that the branches are up to date with the remote
sh "git pull"
end
puts "* Updating Bundle"
silent_sh('bundle update')
begin
unless ENV['SKIP_SPECS']
puts "* Running specs"
silent_sh('rake spec:all')
task :build do
title "Building the gem"
end
tmp = File.expand_path('../tmp', __FILE__)
tmp_gems = File.join(tmp, 'gems')
Rake::Task['gem:build'].invoke
require "bundler/gem_tasks"
puts "* Testing gem installation (tmp/gems)"
silent_sh "rm -rf '#{tmp}'"
silent_sh "gem install --install-dir='#{tmp_gems}' #{gem_filename}"
# Post release
#-----------------------------------------------------------------------------#
# Then release
sh "git commit lib/cocoapods/gem_version.rb CHANGELOG.md Gemfile.lock -m 'Release #{gem_version}'"
sh "git tag -a #{gem_version} -m 'Release #{gem_version}'"
sh "git push origin master"
sh "git push origin --tags"
sh "gem push #{gem_filename}"
# Update the last version in CocoaPods-version.yml
puts "* Updating last known version in Specs repo"
desc "Updates the last know version of CocoaPods in the specs repo"
task :post_release do
title "Updating last known version in Specs repo"
specs_branch = 'master'
Dir.chdir('../Specs') do
puts Dir.pwd
......@@ -136,7 +57,7 @@ namespace :gem do
yaml_file = 'CocoaPods-version.yml'
unless File.exist?(yaml_file)
$stderr.puts "[!] Unable to find #{yaml_file}!"
$stderr.puts red("[!] Unable to find #{yaml_file}!")
exit 1
end
require 'yaml'
......@@ -150,14 +71,14 @@ namespace :gem do
sh "git push"
end
end
end
#-----------------------------------------------------------------------------#
# Spec
#-----------------------------------------------------------------------------#
namespace :spec do
namespace :spec do
def specs(dir)
FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
FileList["spec/#{dir}_spec.rb"].shuffle.join(' ')
end
#--------------------------------------#
......@@ -169,7 +90,7 @@ namespace :spec do
#--------------------------------------#
unit_specs_command = "bundle exec bacon #{specs('unit/**')}"
unit_specs_command = "bundle exec bacon #{specs('unit/**/*')}"
desc "Run the unit specs"
task :unit => :unpack_fixture_tarballs do
......@@ -184,8 +105,9 @@ namespace :spec do
#--------------------------------------#
desc "Run the functional specs"
task :functional => :unpack_fixture_tarballs do
sh "bundle exec bacon #{specs('functional/**')}"
task :functional, [:spec] => :unpack_fixture_tarballs do |t, args|
args.with_defaults(:spec => '**/*')
sh "bundle exec bacon #{specs("functional/#{args[:spec]}")}"
end
#--------------------------------------#
......@@ -193,7 +115,7 @@ namespace :spec do
desc "Run the integration spec"
task :integration do
unless File.exists?('spec/cocoapods-integration-specs')
$stderr.puts "Integration files not checked out. Run `rake bootstrap`"
$stderr.puts red("Integration files not checked out. Run `rake bootstrap`")
exit 1
end
......@@ -208,32 +130,10 @@ namespace :spec do
#
task :all => :unpack_fixture_tarballs do
ENV['GENERATE_COVERAGE'] = 'true'
puts "\033[0;32mUsing #{`ruby --version`}\033[0m"
title 'Running the specs'
sh "bundle exec bacon #{specs('**')}"
title 'Running Integration tests'
sh "bundle exec bacon spec/integration.rb"
title 'Running examples'
Rake::Task['examples:build'].invoke
end
# Travis
#--------------------------------------#
#
# The integration 2 tests and the examples use the normal CocoaPods setup.
#
desc "Run all specs and build all examples"
task :ci => :unpack_fixture_tarballs do
title 'Running the specs'
sh "bundle exec bacon #{specs('**')}"
require 'pathname'
unless Pathname.new(ENV['HOME']+'/.cocoapods/repos/master').exist?
title 'Ensuring specs repo is up to date'
sh "./bin/pod setup"
end
sh "bundle exec bacon #{specs('**/*')}"
title 'Running Integration tests'
sh "bundle exec bacon spec/integration.rb"
......@@ -242,8 +142,6 @@ namespace :spec do
Rake::Task['examples:build'].invoke
end
#--------------------------------------#
desc "Rebuild all the fixture tarballs"
task :rebuild_fixture_tarballs do
tarballs = FileList['spec/fixtures/**/*.tar.gz']
......@@ -253,8 +151,6 @@ namespace :spec do
end
end
#--------------------------------------#
desc "Unpacks all the fixture tarballs"
task :unpack_fixture_tarballs do
tarballs = FileList['spec/fixtures/**/*.tar.gz']
......@@ -266,19 +162,16 @@ namespace :spec do
end
end
#--------------------------------------#
desc "Removes the stored VCR fixture"
task :clean_vcr do
sh "rm -f spec/fixtures/vcr/tarballs.yml"
end
#--------------------------------------#
desc "Rebuilds integration fixtures"
task :rebuild_integration_fixtures do
title 'Running Integration tests'
`bundle exec bacon spec/integration.rb`
sh 'rm -rf spec/cocoapods-integration-specs/tmp'
puts `bundle exec bacon spec/integration.rb`
title 'Storing fixtures'
# Copy the files to the files produced by the specs to the after folders
......@@ -302,15 +195,14 @@ namespace :spec do
puts "Integration fixtures updated, commit and push in the `spec/cocoapods-integration-specs` submodule"
end
#--------------------------------------#
task :clean_env => [:clean_vcr, :unpack_fixture_tarballs, "ext:cleanbuild"]
end
end
#-----------------------------------------------------------------------------#
# Examples
#-----------------------------------------------------------------------------#
task :examples => "examples:build"
namespace :examples do
task :examples => "examples:build"
namespace :examples do
desc "Open all example workspaces in Xcode, which recreates the schemes."
task :recreate_workspace_schemes do
......@@ -324,13 +216,14 @@ namespace :examples do
end
end
#--------------------------------------#
desc "Build all examples"
task :build do
Dir.chdir("examples/AFNetworking Example") do
puts "Installing Pods"
pod_command = ENV['FROM_GEM'] ? 'sandbox-pod' : 'bundle exec ../../bin/sandbox-pod'
# pod_command = ENV['FROM_GEM'] ? 'sandbox-pod' : 'bundle exec ../../bin/sandbox-pod'
# TODO: The sandbox is blocking local git repos making bundler crash
pod_command = ENV['FROM_GEM'] ? 'sandbox-pod' : 'bundle exec ../../bin/pod'
execute_command "rm -rf Pods"
execute_command "#{pod_command} install --verbose --no-repo-update"
......@@ -347,41 +240,40 @@ namespace :examples do
sdk = Dir.glob("#{`xcode-select -print-path`.chomp}/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator*.sdk").last
execute_command "xcodebuild -workspace 'AFNetworking Examples.xcworkspace' -scheme 'AFNetworking iOS Example' clean install ONLY_ACTIVE_ARCH=NO -sdk #{sdk}"
end
end
end
end
#--------------------------------------#
#-----------------------------------------------------------------------------#
end
desc "Run all specs"
task :spec => 'spec:all'
#-----------------------------------------------------------------------------#
task :default => :spec
desc "Initializes your working copy to run the specs"
task :bootstrap, :use_bundle_dir? do |t, args|
title "Environment bootstrap"
rescue LoadError
$stderr.puts "\033[0;31m" \
'[!] Some Rake tasks haven been disabled because the environment' \
' couldn’t be loaded. Be sure to run `rake bootstrap` first.' \
"\e[0m"
end
puts "Updating submodules"
execute_command "git submodule update --init --recursive"
# Helpers
#-----------------------------------------------------------------------------#
puts "Installing gems"
if args[:use_bundle_dir?]
execute_command "env XCODEPROJ_BUILD=1 bundle install --path ./travis_bundle_dir"
def execute_command(command)
if ENV['VERBOSE']
sh(command)
else
execute_command "env XCODEPROJ_BUILD=1 bundle install"
output = `#{command} 2>&1`
raise output unless $?.success?
end
end
#-----------------------------------------------------------------------------#
desc "Run all specs"
task :spec => 'spec:all'
task :default => :spec
#-----------------------------------------------------------------------------#
# group helpers
def gem_version
require File.expand_path('../lib/cocoapods/gem_version.rb', __FILE__)
Pod::VERSION
end
def title(title)
cyan_title = "\033[0;36m#{title}\033[0m"
......@@ -392,3 +284,6 @@ def title(title)
puts
end
def red(string)
"\033[0;31m#{string}\e[0m"
end
#!/usr/bin/env ruby
if RUBY_VERSION > '1.8.7' && Encoding.default_external != Encoding::UTF_8
puts "\e[33mWARNING: CocoaPods requires your terminal to be using UTF-8 encoding."
if ENV["TRAVIS"]
puts <<-DOC
Consider adding the following settings to .travis.yml
before_script:
- export LANG=en_US.UTF-8\e[0m\n
DOC
else
puts <<-DOC
\e[33mWARNING: CocoaPods requires your terminal to be using UTF-8 encoding.
See https://github.com/CocoaPods/guides.cocoapods.org/issues/26 for
possible solutions.\e[0m\n
DOC
end
end
if $PROGRAM_NAME == __FILE__ && !ENV['COCOAPODS_NO_BUNDLER']
......
......@@ -28,17 +28,19 @@ s.files = Dir["lib/**/*.rb"] + %w{ bin/pod bin/sandbox-pod README.md LICENSE CHA
# Link with the version of CocoaPods-Core
s.add_runtime_dependency 'cocoapods-core', "= #{Pod::VERSION}"
s.add_runtime_dependency 'claide', '~> 0.4.0'
s.add_runtime_dependency 'cocoapods-downloader', '~> 0.3.0'
s.add_runtime_dependency 'xcodeproj', '~> 0.14.1'
s.add_runtime_dependency 'cocoapods-try-release-fix', '~> 0.1.1'
s.add_runtime_dependency 'claide', '~> 0.6.1'
s.add_runtime_dependency 'xcodeproj', '~> 0.18.0'
s.add_runtime_dependency 'cocoapods-downloader', '~> 0.6.1'
s.add_runtime_dependency 'cocoapods-plugins', '~> 0.2.0'
s.add_runtime_dependency 'cocoapods-try', '~> 0.3.0'
s.add_runtime_dependency 'cocoapods-trunk', '~> 0.1.4'
s.add_runtime_dependency 'colored', '~> 1.2'
s.add_runtime_dependency 'escape', '~> 0.0.4'
s.add_runtime_dependency 'json_pure', '~> 1.8'
s.add_runtime_dependency 'open4', '~> 1.3'
s.add_runtime_dependency 'activesupport', '>= 3.2.15', '< 4'
s.add_runtime_dependency 'nap', '~> 0.5'
s.add_runtime_dependency 'nap', '~> 0.8'
s.add_development_dependency 'bacon', '~> 1.1'
......
......@@ -9,7 +9,10 @@ require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/array/conversions'
# TODO check what this actually does by the time we're going to add support for
# other locales.
I18n.enforce_available_locales = false
require 'i18n'
if I18n.respond_to?(:enforce_available_locales=)
I18n.enforce_available_locales = false
end
module Pod
require 'pathname'
......@@ -19,6 +22,11 @@ module Pod
require 'cocoapods/config'
require 'cocoapods/downloader'
# Loaded immediately after dependencies to ensure proper override of their
# UI methods.
#
require 'cocoapods/user_interface'
# Indicates an user error. This is defined in cocoapods-core.
#
class Informative < PlainInformative
......@@ -38,7 +46,6 @@ module Pod
autoload :Project, 'cocoapods/project'
autoload :Resolver, 'cocoapods/resolver'
autoload :Sandbox, 'cocoapods/sandbox'
autoload :UI, 'cocoapods/user_interface'
autoload :Validator, 'cocoapods/validator'
module Generator
......
......@@ -14,23 +14,24 @@ module Pod
require 'cocoapods/command/list'
require 'cocoapods/command/outdated'
require 'cocoapods/command/project'
require 'cocoapods/command/push'
require 'cocoapods/command/repo'
require 'cocoapods/command/search'
require 'cocoapods/command/setup'
require 'cocoapods/command/spec'
require 'cocoapods/command/init'
# TODO: remove
require 'cocoapods/command/push'
self.abstract_command = true
self.default_subcommand = 'install'
self.command = 'pod'
self.version = VERSION
self.description = 'CocoaPods, the Objective-C library package manager.'
self.plugin_prefix = 'cocoapods'
def self.options
[
['--silent', 'Show nothing'],
['--version', 'Show the version of CocoaPods'],
].concat(super)
end
......@@ -43,11 +44,7 @@ module Pod
end
def self.run(argv)
argv = CLAide::ARGV.new(argv)
if argv.flag?('version')
UI.puts VERSION
exit 0
end
help! "You cannot run CocoaPods as root." if Process.uid == 0
super(argv)
UI.print_warnings
end
......
......@@ -2,7 +2,9 @@ module Pod
class Command
class Help < Command
self.summary = 'Show help for the given command.'
self.arguments = '[COMMAND]'
self.arguments = [
CLAide::Argument.new('COMMAND', false)
]
def initialize(argv)
@help_command = Pod::Command.parse(argv)
......
......@@ -8,16 +8,18 @@ module Pod
self.summary = 'Generate a Podfile for the current directory.'
self.description = <<-DESC
Creates a Podfile for the current directory if none currently exists. If
an Xcode project file is specified or if there is only a single project
file in the current directory, targets will be automatically generated
based on targets defined in the project.
an `XCODEPROJ` project file is specified or if there is only a single
project file in the current directory, targets will be automatically
generated based on targets defined in the project.
It is possible to specify a list of dependencies which will be used by
the template in the `Podfile.default` (normal targets) `Podfile.test`
(test targets) files which should be stored in the
`~/.cocoapods/templates` folder.
DESC
self.arguments = '[XCODEPROJ]'
self.arguments = [
CLAide::Argument.new('XCODEPROJ', :false)
]
def initialize(argv)
@podfile_path = Pathname.pwd + "Podfile"
......@@ -31,12 +33,13 @@ module Pod
raise Informative, "Existing Podfile found in directory" unless config.podfile.nil?
if @project_path
help! "Xcode project at #{@project_path} does not exist" unless File.exist? @project_path
project_path = @project_path
else
raise Informative, "No xcode project found, please specify one" unless @project_paths.length > 0
raise Informative, "Multiple xcode projects found, please specify one" unless @project_paths.length == 1
@project_path = @project_paths.first
project_path = @project_paths.first
end
@xcode_project = Xcodeproj::Project.open(@project_path)
@xcode_project = Xcodeproj::Project.open(project_path)
end
def run
......@@ -51,7 +54,9 @@ module Pod
# @return [String] the text of the Podfile for the provided project
#
def podfile_template(project)
podfile = <<-PLATFORM.strip_heredoc
podfile = ''
podfile << "xcodeproj '#{@project_path}'\n\n" if @project_path
podfile << <<-PLATFORM.strip_heredoc
# Uncomment this line to define a global platform for your project
# platform :ios, "6.0"
PLATFORM
......
......@@ -15,7 +15,9 @@ module Pod
self.summary = 'Converts a podspec to JSON.'
self.description = 'Converts a podspec to JSON and prints it to STDOUT.'
self.arguments = 'PATH'
self.arguments = [
CLAide::Argument.new('PATH', true)
]
def initialize(argv)
@path = argv.shift_argument
......@@ -40,7 +42,9 @@ module Pod
self.summary = 'Converts a Podfile to YAML.'
self.description = 'Converts a Podfile to YAML and prints it to STDOUT.'
self.arguments = 'PATH'
self.arguments = [
CLAide::Argument.new('PATH', true)
]
def initialize(argv)
@path = argv.shift_argument
......@@ -63,11 +67,11 @@ module Pod
class List < IPC
self.summary = 'Lists the specifications know to CocoaPods.'
self.summary = 'Lists the specifications known to CocoaPods.'
self.description = <<-DESC
Prints to STDOUT a YAML dictionary where the keys are the name of the
specifications and the values are a dictionary with the following
keys.
specifications and each corresponding value is a dictionary with
the following keys:
- defined_in_file
- version
......
......@@ -10,13 +10,20 @@ module Pod
self.summary = 'Creates a new Pod'
self.description = <<-DESC
Creates a new Pod with the given name from the template in the working directory.
Creates a scaffold for the development of a new Pod named `NAME`
according to the CocoaPods best practices.
If a `TEMPLATE_URL`, pointing to a git repo containing a compatible
template, is specified, it will be used in place of the default one.
DESC
self.arguments = '[NAME]'
self.arguments = [
CLAide::Argument.new('NAME', true),
CLAide::Argument.new('TEMPLATE_URL', false)
]
def initialize(argv)
@name = argv.shift_argument
@template_url = argv.shift_argument
super
end
......@@ -24,6 +31,7 @@ module Pod
super
help! "A name for the Pod is required." unless @name
help! "The Pod name cannot contain spaces." if @name.match(/\s/)
help! "The Pod name cannot begin with a '.'" if @name[0, 1] == '.'
end
def run
......@@ -52,8 +60,8 @@ module Pod
# @return [void]
#
def clone_template
UI.section("Creating `#{@name}` Pod") do
git!"clone '#{TEMPLATE_REPO}' #{@name}"
UI.section("Cloning `#{template_repo_url}` into `#{@name}`.") do
git!"clone '#{template_repo_url}' #{@name}"
end
end
......@@ -62,9 +70,13 @@ module Pod
# @return [void]
#
def configure_template
UI.section("Configuring template") do
UI.section("Configuring #{@name} template.") do
Dir.chdir(@name) do
ruby! "_CONFIGURE.rb #{@name}"
if File.exists? "configure"
system "./configure #{@name}"
else
UI.warn "Template does not have a configure file."
end
end
end
end
......@@ -74,10 +86,17 @@ module Pod
# @return [void]
#
def print_info
UI.puts "\nTo learn more about the template see `#{TEMPLATE_INFO_URL}`."
UI.puts "\nTo learn more about the template see `#{template_repo_url}`."
UI.puts "To learn more about creating a new pod, see `#{CREATE_NEW_POD_INFO_URL}`."
end
# Checks if a template URL is given else returns the TEMPLATE_REPO URL
#
# @return String
#
def template_repo_url
@template_url || TEMPLATE_REPO
end
end
#-----------------------------------------------------------------------#
......
......@@ -24,7 +24,7 @@ module Pod
update_if_necessary!
sets = SourcesManager.all_sets
sets.each { |set| UI.pod(set, :name) }
sets.each { |set| UI.pod(set, :name_and_version) }
UI.puts "\n#{sets.count} pods were found"
end
......
......@@ -23,21 +23,6 @@ module Pod
# @todo fix.
#
def run
verify_podfile_exists!
verify_lockfile_exists!
lockfile = config.lockfile
pods = lockfile.pod_names
updates = []
pods.each do |pod_name|
set = SourcesManager.search(Dependency.new(pod_name))
next unless set
source_version = set.versions.first
lockfile_version = lockfile.version(pod_name)
if source_version > lockfile_version
updates << [pod_name, lockfile_version, source_version]
end
end
if updates.empty?
UI.puts "No updates are available.".yellow
......@@ -48,8 +33,72 @@ module Pod
end
end
end
if deprecated_pods.any?
UI.section 'The following pods are deprecated:' do
deprecated_pods.each do |spec|
if spec.deprecated_in_favor_of
UI.puts "- #{spec.name}" \
" (in favor of #{spec.deprecated_in_favor_of})"
else
UI.puts "- #{spec.name}"
end
end
end
end
end
private
def updates
@updates ||= begin
spec_sets.map do |set|
spec = set.specification
source_version = set.versions.first
pod_name = spec.root.name
lockfile_version = lockfile.version(pod_name)
if source_version > lockfile_version
[pod_name, lockfile_version, source_version]
else
nil
end
end.compact.uniq
end
end
def deprecated_pods
@deprecated_pods ||= begin
spec_sets.map(&:specification).select do |spec|
spec.deprecated || spec.deprecated_in_favor_of
end.compact.uniq
end
end
def spec_sets
@spec_sets ||= begin
installed_pods.map do |pod_name|
SourcesManager.search(Dependency.new(pod_name))
end.compact.uniq
end
end
def installed_pods
@installed_pods ||= begin
verify_podfile_exists!
lockfile.pod_names
end
end
def lockfile
@lockfile ||= begin
verify_lockfile_exists!
config.lockfile
end
end
end
end
end
......
......@@ -8,7 +8,7 @@ module Pod
module Options
def options
[
["--no-clean", "Leave SCM dirs like `.git' and `.svn' intact after downloading"],
["--no-clean", "Leave SCM dirs like `.git` and `.svn` intact after downloading"],
["--no-integrate", "Skip integration of the Pods libraries in the Xcode project(s)"],
["--no-repo-update", "Skip running `pod repo update` before install"],
].concat(super)
......@@ -28,13 +28,15 @@ module Pod
# Runs the installer.
#
# @param [update] whether the installer should be run in update mode.
# @param [Hash, Boolean, nil] update
# Pods that have been requested to be updated or true if all Pods
# should be updated
#
# @return [void]
#
def run_install_with_update(update)
installer = Installer.new(config.sandbox, config.podfile, config.lockfile)
installer.update_mode = update
installer.update = update
installer.install!
end
end
......@@ -44,11 +46,11 @@ module Pod
class Install < Command
include Project
self.summary = 'Install project dependencies'
self.summary = 'Install project dependencies to Podfile.lock versions'
self.description = <<-DESC
Downloads all dependencies defined in `Podfile' and creates an Xcode
Pods library project in `./Pods'.
Downloads all dependencies defined in `Podfile` and creates an Xcode
Pods library project in `./Pods`.
The Xcode project file should be specified in your `Podfile` like this:
......@@ -74,14 +76,47 @@ module Pod
class Update < Command
include Project
self.summary = 'Update outdated project dependencies'
self.summary = 'Update outdated project dependencies and create new Podfile.lock'
self.description = <<-DESC
Updates the Pods identified by the specified `POD_NAMES`. If no
`POD_NAMES` are specified it updates all the Pods ignoring the contents
of the Podfile.lock.
This command is reserved to the update of dependencies and pod install
should be used to install changes to the Podfile.
DESC
self.arguments = [
CLAide::Argument.new('POD_NAMES', false, true),
]
def initialize(argv)
@pods = argv.arguments! unless argv.arguments.empty?
super
end
def run
verify_podfile_exists!
if @pods
verify_lockfile_exists!
# Check if all given pods are installed
missing_pods = @pods.select { |pod| !config.lockfile.pod_names.include?(pod) }
if missing_pods.length > 0
raise Informative, (missing_pods.length > 1 \
? "Pods %s are not installed and cannot be updated" \
: "Pod %s is not installed and cannot be updated"
) % missing_pods.map { |p| "`#{p}`" }.join(', ')
end
run_install_with_update(:pods => @pods)
else
UI.puts "Update all pods".yellow unless @pods
run_install_with_update(true)
end
end
end
end
end
......
require 'fileutils'
require 'active_support/core_ext/string/inflections'
module Pod
class Command
class Push < Command
self.summary = 'Push new specifications to a spec-repo'
self.description = <<-DESC
Validates NAME.podspec or `*.podspec' in the current working dir, creates
a directory and version folder for the pod in the local copy of
REPO (~/.cocoapods/repos/[REPO]), copies the podspec file into the version
directory, and finally it pushes REPO to its remote.
DESC
self.arguments = 'REPO [NAME.podspec]'
self.summary = 'Temporary alias for the `pod repo push` command'
def self.options
[ ["--allow-warnings", "Allows pushing even if there are warnings"],
["--local-only", "Does not perform the step of pushing REPO to its remote"] ].concat(super)
end
def initialize(argv)
@allow_warnings = argv.flag?('allow-warnings')
@local_only = argv.flag?('local-only')
@repo = argv.shift_argument
if @repo.nil?
@repo = "master"
elsif @repo.end_with? ".podspec"
@podspec = @repo
@repo = "master"
else
@podspec = argv.shift_argument
end
@push_command = Repo::Push.new(argv)
super
end
def validate!
super
help! "A spec-repo name is required." unless @repo
UI.puts '[!] The `pod push` command has been moved to `pod repo push`.'.ansi.yellow
@push_command.validate!
end
def run
validate_podspec_files
test_trunk
check_repo_status
update_repo
add_specs_to_repo
push_repo unless @local_only
end
#-----------------------------------------------------------------------#
private
# @!group Push sub-steps
extend Executable
executable :git
# @return [void] Silently test the CocoaPods trunk service.
#
def test_trunk
return unless @repo == "master"
require 'rest'
base_url = 'https://trunk.cocoapods.org/api/v1'
podspec_files.each do |spec_file|
spec = Pod::Specification.from_file(spec_file)
REST.post("#{base_url}/pods", spec.to_json, 'Content-Type' => 'application/json; charset=utf-8',
'Authorization' => "Token 9300632274827cd3e6dde24bf9c608c3")
end
rescue Exception
# Nothing
end
# Performs a full lint against the podspecs.
#
def validate_podspec_files
UI.puts "\nValidating #{'spec'.pluralize(count)}".yellow
podspec_files.each do |podspec|
validator = Validator.new(podspec)
validator.only_errors = @allow_warnings
begin
validator.validate
rescue Exception
raise Informative, "The `#{podspec}` specification does not validate."
end
raise Informative, "The `#{podspec}` specification does not validate." unless validator.validated?
end
end
# Checks that the repo is clean.
#
# @raise If the repo is not clean.
#
# @todo Add specs for staged and unstaged files.
#
# @todo Gracefully handle the case where source is not under git
# source control.
#
# @return [void]
#
def check_repo_status
clean = Dir.chdir(repo_dir) { `git status --porcelain 2>&1` } == ''
raise Informative, "The repo `#{@repo}` is not clean" unless clean
end
# Updates the git repo against the remote.
#
# @return [void]
#
def update_repo
UI.puts "Updating the `#{@repo}' repo\n".yellow
Dir.chdir(repo_dir) { UI.puts `git pull 2>&1` }
@push_command.run
end
# Commits the podspecs to the source, which should be a git repo.
#
# @note The pre commit hook of the repo is skipped as the podspecs have
# already been linted.
#
# @return [void]
#
def add_specs_to_repo
UI.puts "\nAdding the #{'spec'.pluralize(count)} to the `#{@repo}' repo\n".yellow
podspec_files.each do |spec_file|
spec = Pod::Specification.from_file(spec_file)
output_path = File.join(repo_dir, spec.name, spec.version.to_s)
if Pathname.new(output_path).exist?
message = "[Fix] #{spec}"
elsif Pathname.new(File.join(repo_dir, spec.name)).exist?
message = "[Update] #{spec}"
else
message = "[Add] #{spec}"
end
FileUtils.mkdir_p(output_path)
FileUtils.cp(spec_file, output_path)
Dir.chdir(repo_dir) do
# only commit if modified
if git!("status --porcelain 2>&1") =~ /#{spec.name}/
UI.puts " - #{message}"
git!("add #{spec.name}")
git!("commit --no-verify -m '#{message}'")
else
UI.puts " - [No change] #{spec}"
end
end
end
end
# Pushes the git repo against the remote.
#
# @return [void]
#
def push_repo
UI.puts "\nPushing the `#{@repo}' repo\n".yellow
Dir.chdir(repo_dir) { UI.puts `git push origin master 2>&1` }
end
#-----------------------------------------------------------------------#
private
# @!group Private helpers
# @return [Pathname] The directory of the repository.
#
def repo_dir
dir = config.repos_dir + @repo
raise Informative, "`#{@repo}` repo not found" unless dir.exist?
dir
end
# @return [Array<Pathname>] The path of the specifications to push.
#
def podspec_files
files = Pathname.glob(@podspec || "*.podspec")
raise Informative, "Couldn't find any .podspec file in current directory" if files.empty?
files
end
# @return [Integer] The number of the podspec files to push.
#
def count
podspec_files.count
end
#-----------------------------------------------------------------------#
end
end
end
require 'fileutils'
require 'cocoapods/command/repo/push'
module Pod
class Command
......@@ -17,9 +18,20 @@ module Pod
remote can later be referred to by `NAME`.
DESC
self.arguments = 'NAME URL [BRANCH]'
self.arguments = [
CLAide::Argument.new('NAME', true),
CLAide::Argument.new('URL', true),
CLAide::Argument.new('BRANCH', false)
]
def self.options
[
["--shallow", "Create a shallow clone (fast clone, but no push capabilities)"],
].concat(super)
end
def initialize(argv)
@shallow = argv.flag?('shallow', false)
@name, @url, @branch = argv.shift_argument, argv.shift_argument, argv.shift_argument
super
end
......@@ -32,9 +44,14 @@ module Pod
end
def run
UI.section("Cloning spec repo `#{@name}` from `#{@url}`#{" (branch `#{@branch}`)" if @branch}") do
prefix = @shallow ? 'Creating shallow clone of' : 'Cloning'
UI.section("#{prefix} spec repo `#{@name}` from `#{@url}`#{" (branch `#{@branch}`)" if @branch}") do
config.repos_dir.mkpath
Dir.chdir(config.repos_dir) { git!("clone '#{@url}' #{@name}") }
Dir.chdir(config.repos_dir) do
command = "clone '#{@url}' #{@name}"
command << ' --depth=1' if @shallow
git!(command)
end
Dir.chdir(dir) { git!("checkout #{@branch}") } if @branch
SourcesManager.check_version_information(dir)
end
......@@ -51,7 +68,9 @@ module Pod
this will update all spec-repos in `~/.cocoapods/repos`.
DESC
self.arguments = '[NAME]'
self.arguments = [
CLAide::Argument.new('NAME', false)
]
def initialize(argv)
@name = argv.shift_argument
......@@ -74,7 +93,9 @@ module Pod
will lint all the spec-repos known to CocoaPods.
DESC
self.arguments = '[ NAME | DIRECTORY ]'
self.arguments = [
CLAide::Argument.new(%w(NAME DIRECTORY), false)
]
def self.options
[["--only-errors", "Lint presents only the errors"]].concat(super)
......@@ -140,7 +161,9 @@ module Pod
Deletes the remote named `NAME` from the local spec-repos directory at `~/.cocoapods/repos/.`
DESC
self.arguments = 'NAME'
self.arguments = [
CLAide::Argument.new('NAME', true)
]
def initialize(argv)
@name = argv.shift_argument
......@@ -151,6 +174,8 @@ module Pod
super
help! 'Deleting a repo needs a `NAME`.' unless @name
help! "repo #{@name} does not exist" unless File.directory?(dir)
help! "You do not have permission to delete the #{@name} repository." \
"Perhaps try prefixing this command with sudo." unless File.writable?(dir)
end
def run
......
require 'fileutils'
require 'active_support/core_ext/string/inflections'
module Pod
class Command
class Repo < Command
class Push < Repo
self.summary = 'Push new specifications to a spec-repo'
self.description = <<-DESC
Validates `NAME.podspec` or `*.podspec` in the current working dir,
creates a directory and version folder for the pod in the local copy of
`REPO` (~/.cocoapods/repos/[REPO]), copies the podspec file into the
version directory, and finally it pushes `REPO` to its remote.
DESC
self.arguments = [
CLAide::Argument.new('REPO', true),
CLAide::Argument.new('NAME.podspec', false)
]
def self.options
[ ["--allow-warnings", "Allows pushing even if there are warnings"],
["--local-only", "Does not perform the step of pushing REPO to its remote"] ].concat(super)
end
def initialize(argv)
@allow_warnings = argv.flag?('allow-warnings')
@local_only = argv.flag?('local-only')
@repo = argv.shift_argument
@podspec = argv.shift_argument
super
end
def validate!
super
help! "A spec-repo name is required." unless @repo
end
def run
check_if_master_repo
validate_podspec_files
check_repo_status
update_repo
add_specs_to_repo
push_repo unless @local_only
end
#---------------------------------------------------------------------#
private
# @!group Push sub-steps
extend Executable
executable :git
# Temporary check to ensure that users do not push accidentally private
# specs to the master repo.
#
def check_if_master_repo
remotes = Dir.chdir(repo_dir) { `git remote -v 2>&1` }
master_repo_urls = [
'git@github.com:CocoaPods/Specs.git',
'https://github.com/CocoaPods/Specs.git',
]
is_master_repo = master_repo_urls.any? do |url|
remotes.include?(url)
end
if is_master_repo
raise Informative, "To push to the CocoaPods master repo use " \
"the `pod trunk push` command.\n\nIf you are using a fork of " \
"the master repo for private purposes we recommend to migrate " \
"to a clean private repo. To disable this check remove the " \
"remote pointing to the CocoaPods master repo."
end
end
# Performs a full lint against the podspecs.
#
def validate_podspec_files
UI.puts "\nValidating #{'spec'.pluralize(count)}".yellow
podspec_files.each do |podspec|
validator = Validator.new(podspec)
validator.only_errors = @allow_warnings
begin
validator.validate
rescue Exception
raise Informative, "The `#{podspec}` specification does not validate."
end
raise Informative, "The `#{podspec}` specification does not validate." unless validator.validated?
end
end
# Checks that the repo is clean.
#
# @raise If the repo is not clean.
#
# @todo Add specs for staged and unstaged files.
#
# @todo Gracefully handle the case where source is not under git
# source control.
#
# @return [void]
#
def check_repo_status
clean = Dir.chdir(repo_dir) { `git status --porcelain 2>&1` } == ''
raise Informative, "The repo `#{@repo}` is not clean" unless clean
end
# Updates the git repo against the remote.
#
# @return [void]
#
def update_repo
UI.puts "Updating the `#{@repo}' repo\n".yellow
Dir.chdir(repo_dir) { UI.puts `git pull 2>&1` }
end
# Commits the podspecs to the source, which should be a git repo.
#
# @note The pre commit hook of the repo is skipped as the podspecs have
# already been linted.
#
# @return [void]
#
def add_specs_to_repo
UI.puts "\nAdding the #{'spec'.pluralize(count)} to the `#{@repo}' repo\n".yellow
podspec_files.each do |spec_file|
spec = Pod::Specification.from_file(spec_file)
output_path = File.join(repo_dir, spec.name, spec.version.to_s)
if Pathname.new(output_path).exist?
message = "[Fix] #{spec}"
elsif Pathname.new(File.join(repo_dir, spec.name)).exist?
message = "[Update] #{spec}"
else
message = "[Add] #{spec}"
end
FileUtils.mkdir_p(output_path)
FileUtils.cp(spec_file, output_path)
Dir.chdir(repo_dir) do
# only commit if modified
if git!("status --porcelain 2>&1").include?(spec.name)
UI.puts " - #{message}"
git!("add #{spec.name}")
git!("commit --no-verify -m '#{message}'")
else
UI.puts " - [No change] #{spec}"
end
end
end
end
# Pushes the git repo against the remote.
#
# @return [void]
#
def push_repo
UI.puts "\nPushing the `#{@repo}' repo\n".yellow
Dir.chdir(repo_dir) { UI.puts `git push origin master 2>&1` }
end
#---------------------------------------------------------------------#
private
# @!group Private helpers
# @return [Pathname] The directory of the repository.
#
def repo_dir
specs_dir = Pathname.new(File.join(config.repos_dir, @repo, 'Specs'))
dir = config.repos_dir + @repo
if specs_dir.exist?
dir = specs_dir
elsif dir.exist?
dir
else
raise Informative, "`#{@repo}` repo not found either in #{specs_dir} or #{dir}"
end
dir
end
# @return [Array<Pathname>] The path of the specifications to push.
#
def podspec_files
files = Pathname.glob(@podspec || "*.podspec")
raise Informative, "Couldn't find any .podspec file in current directory" if files.empty?
files
end
# @return [Integer] The number of the podspec files to push.
#
def count
podspec_files.count
end
#---------------------------------------------------------------------#
end
end
end
end
......@@ -4,12 +4,14 @@ module Pod
self.summary = 'Searches for pods'
self.description = <<-DESC
Searches for pods, ignoring case, whose name matches `QUERY'. If the
`--full' option is specified, this will also search in the summary and
Searches for pods, ignoring case, whose name matches `QUERY`. If the
`--full` option is specified, this will also search in the summary and
description of the pods.
DESC
self.arguments = '[QUERY]'
self.arguments = [
CLAide::Argument.new('QUERY', true)
]
def self.options
[
......@@ -35,6 +37,14 @@ module Pod
def validate!
super
help! "A search query is required." unless @query
unless @web
begin
/#{@query.join(' ').strip}/
rescue RegexpError
help! "A valid regular expression is required."
end
end
end
def run
......@@ -50,11 +60,11 @@ module Pod
def web_search
query_parameter = [
('on%3Aosx' if @supported_on_osx),
('on%3Aios' if @supported_on_ios),
('on:osx' if @supported_on_osx),
('on:ios' if @supported_on_ios),
@query
].compact.flatten.join('%20')
url = "http://cocoapods.org/?q=#{query_parameter}"
].compact.flatten.join(' ')
url = "http://cocoapods.org/?q=#{CGI.escape(query_parameter).gsub("+", "%20")}"
UI.puts("Opening #{url}")
open!(url)
end
......
......@@ -15,7 +15,10 @@ module Pod
DESC
def self.options
[["--push", "Use this option to enable push access once granted"]].concat(super)
[
["--no-shallow", "Clone full history so push will work"],
["--push", "Use this option to enable push access once granted"],
].concat(super)
end
extend Executable
......@@ -23,6 +26,7 @@ module Pod
def initialize(argv)
@push_option = argv.flag?('push')
@shallow = argv.flag?('shallow', !@push_option)
super
end
......@@ -77,7 +81,9 @@ module Pod
# @return [void]
#
def add_master_repo
@command ||= Repo::Add.parse(['master', url, 'master']).run
cmd = ['master', url, 'master']
cmd << '--shallow' if @shallow
Repo::Add.parse(cmd).run
end
# Updates the master repo against the remote.
......@@ -109,7 +115,7 @@ module Pod
# be enabled.
#
def url
(push?) ? read_write_url : read_only_url
push? ? read_write_url : read_only_url
end
# @return [String] the read only url of the master repo.
......
......@@ -18,7 +18,9 @@ module Pod
If a GitHub url is passed the spec is prepopulated.
DESC
self.arguments = '[ NAME | https://github.com/USER/REPO ]'
self.arguments = [
CLAide::Argument.new(%w(NAME https://github.com/USER/REPO), false)
]
def initialize(argv)
@name_or_url, @url = argv.shift_argument, argv.shift_argument
......@@ -51,12 +53,14 @@ module Pod
self.summary = 'Validates a spec file.'
self.description = <<-DESC
Validates `NAME.podspec'. If a directory is provided it validates
Validates `NAME.podspec`. If a `DIRECTORY` is provided, it validates
the podspec files found, including subfolders. In case
the argument is omitted, it defaults to the current working dir.
DESC
self.arguments = '[ NAME.podspec | DIRECTORY | http://PATH/NAME.podspec, ... ]'
self.arguments = [
CLAide::Argument.new(%w(NAME.podspec DIRECTORY http://PATH/NAME.podspec), false, true),
]
def self.options
[ ["--quick", "Lint skips checks that would require to download and build the spec"],
......@@ -122,7 +126,7 @@ module Pod
end
files << output_path
else if (pathname = Pathname.new(path)).directory?
files += Pathname.glob(pathname + '**/*.podspec')
files += Pathname.glob(pathname + '**/*.podspec{.json,}')
raise Informative, "No specs found in the current directory." if files.empty?
else
files << (pathname = Pathname.new(path))
......@@ -148,7 +152,9 @@ module Pod
Prints the path of 'NAME.podspec'
DESC
self.arguments = '[ NAME ]'
self.arguments = [
CLAide::Argument.new('NAME', false)
]
def self.options
[["--show-all", "Print all versions of the given podspec"]].concat(super)
......@@ -180,7 +186,9 @@ module Pod
Prints 'NAME.podspec' to standard output.
DESC
self.arguments = '[ NAME ]'
self.arguments = [
CLAide::Argument.new('NAME', false)
]
def self.options
[["--show-all", "Pick from all versions of the given podspec"]].concat(super)
......@@ -207,7 +215,7 @@ module Pod
get_path_of_spec(@spec)
end
UI.puts File.open(filepath).read
UI.puts File.read(filepath)
end
end
......@@ -220,7 +228,9 @@ module Pod
Opens 'NAME.podspec' to be edited.
DESC
self.arguments = '[ NAME ]'
self.arguments = [
CLAide::Argument.new('NAME', false)
]
def self.options
[["--show-all", "Pick which spec to edit from all available versions of the given podspec"]].concat(super)
......@@ -342,7 +352,7 @@ module Pod
# @return [Pathname] the absolute path of the given spec and source
#
def pathname_from_spec(spec, source)
config.repos_dir + "#{source}/#{spec.name}/#{spec.version}/#{spec.name}.podspec"
Pathname(spec.defined_in_file)
end
# @return [String] of spec paths one on each line
......@@ -370,15 +380,20 @@ module Pod
def spec_and_source_from_set(set)
sources = set.sources
best_source = sources.first
best_version = best_source.versions(set.name).first
best_source = best_version = nil
sources.each do |source|
version = source.versions(set.name).first
if version > best_version
versions = source.versions(set.name)
versions.each do |version|
if !best_version or version > best_version
best_source = source
best_version = version
end
end
end
if !best_source or !best_version
raise Informative, "Unable to locate highest known specification for `#{ set.name }'"
end
return best_source.specification(set.name, best_version), best_source
end
......@@ -475,7 +490,7 @@ Pod::Spec.new do |s|
DESC
s.homepage = "#{data[:homepage]}"
# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
# s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
# ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
......@@ -485,22 +500,22 @@ Pod::Spec.new do |s|
# Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
#
s.license = 'MIT (example)'
# s.license = { :type => 'MIT', :file => 'FILE_LICENSE' }
s.license = "MIT (example)"
# s.license = { :type => "MIT", :file => "FILE_LICENSE" }
# ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the authors of the library, with email addresses. Email addresses
# of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
# accepts just a name if you'd rather not provide an email addresses.
# accepts just a name if you'd rather not provide an email address.
#
# Specify a social_media_url where others can refer to, for example a twitter
# profile URL.
#
s.author = { "#{data[:author_name]}" => "#{data[:author_email]}" }
# Or just: s.author = '#{data[:author_name]}'
# Or just: s.author = "#{data[:author_name]}"
# s.authors = { "#{data[:author_name]}" => "#{data[:author_email]}" }
# s.social_media_url = "http://twitter.com/#{data[:author_name]}"
......@@ -511,11 +526,11 @@ Pod::Spec.new do |s|
#
# s.platform = :ios
# s.platform = :ios, '5.0'
# s.platform = :ios, "5.0"
# When using multiple platforms
# s.ios.deployment_target = '5.0'
# s.osx.deployment_target = '10.7'
# s.ios.deployment_target = "5.0"
# s.osx.deployment_target = "10.7"
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
......@@ -535,10 +550,10 @@ Pod::Spec.new do |s|
# Not including the public_header_files will make all headers public.
#
s.source_files = 'Classes', 'Classes/**/*.{h,m}'
s.exclude_files = 'Classes/Exclude'
s.source_files = "Classes", "Classes/**/*.{h,m}"
s.exclude_files = "Classes/Exclude"
# s.public_header_files = 'Classes/**/*.h'
# s.public_header_files = "Classes/**/*.h"
# ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
......@@ -561,11 +576,11 @@ Pod::Spec.new do |s|
# the lib prefix of their name.
#
# s.framework = 'SomeFramework'
# s.frameworks = 'SomeFramework', 'AnotherFramework'
# s.framework = "SomeFramework"
# s.frameworks = "SomeFramework", "AnotherFramework"
# s.library = 'iconv'
# s.libraries = 'iconv', 'xml2'
# s.library = "iconv"
# s.libraries = "iconv", "xml2"
# ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
......@@ -576,8 +591,8 @@ Pod::Spec.new do |s|
# s.requires_arc = true
# s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2' }
# s.dependency 'JSONKit', '~> 1.4'
# s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
# s.dependency "JSONKit", "~> 1.4"
end
SPEC
......
......@@ -71,7 +71,7 @@ module Pod
output = stdout.join("\n") + stderr.join("\n")
unless status.success?
if raise_on_failure
raise Informative, "#{name} #{command}\n\n#{output}"
raise Informative, "#{full_command}\n\n#{output}"
else
UI.message("[!] Failed: #{full_command}".red)
end
......
require 'cocoapods/external_sources/abstract_external_source'
require 'cocoapods/external_sources/downloader_source'
require 'cocoapods/external_sources/path_source'
require 'cocoapods/external_sources/podspec_source'
module Pod
# Provides support for initializing the correct concrete class of an external
......@@ -13,20 +18,7 @@ module Pod
name = dependency.root_name
params = dependency.external_source
klass = if params.key?(:git) then GitSource
elsif params.key?(:svn) then SvnSource
elsif params.key?(:hg) then MercurialSource
elsif params.key?(:bzr) then BazaarSource
elsif params.key?(:podspec) then PodspecSource
elsif params.key?(:path) then PathSource
end
if params.key?(:local)
klass = PathSource
UI.warn "The `:local` option of the Podfile has been renamed to `:path` and is deprecated." \
end
if klass
if klass = concrete_class_from_params(params)
klass.new(name, params, podfile_path)
else
msg = "Unknown external source parameters for `#{name}`: `#{params}`"
......@@ -34,357 +26,20 @@ module Pod
end
end
#-------------------------------------------------------------------------#
# Abstract class that defines the common behaviour of external sources.
#
class AbstractExternalSource
# @return [String] the name of the Pod described by this external source.
#
attr_reader :name
# @return [Hash{Symbol => String}] the hash representation of the
# external source.
#
attr_reader :params
# @return [String] the path where the podfile is defined to resolve
# relative paths.
#
attr_reader :podfile_path
# @param [String] name @see name
# @param [Hash] params @see params
# @param [String] podfile_path @see podfile_path
#
def initialize(name, params, podfile_path)
@name = name
@params = params
@podfile_path = podfile_path
end
# @return [Bool] whether an external source source is equal to another
# according to the {#name} and to the {#params}.
#
def ==(other)
return false if other.nil?
name == other.name && params == other.params
end
#--------------------------------------#
public
# @!group Fetching
# Fetches the external source from the remote according to the params.
#
# @param [Sandbox] sandbox
# the sandbox where the specification should be stored.
#
# @return [void]
#
def fetch(sandbox)
raise "Abstract method"
end
#--------------------------------------#
public
# @!group Subclasses hooks
# Fetches the external source from the remote according to the params.
#
# @param [Sandbox] sandbox
# the sandbox where the specification should be stored.
#
# @return [void]
#
def fetch(sandbox)
raise "Abstract method"
end
# @return [String] a string representation of the source suitable for UI.
#
def description
raise "Abstract method"
end
#--------------------------------------#
private
# @! Subclasses helpers
# Pre-downloads a Pod passing the options to the downloader and informing
# the sandbox.
#
# @param [Sandbox] sandbox
# The sandbox where the Pod should be downloaded.
#
# @note To prevent a double download of the repository the pod is
# marked as pre-downloaded indicating to the installer that only
# clean operations are needed.
#
# @todo The downloader configuration is the same of the
# #{PodSourceInstaller} and it needs to be kept in sync.
#
# @return [void]
#
def pre_download(sandbox)
UI.titled_section("Pre-downloading: `#{name}` #{description}", { :verbose_prefix => "-> " }) do
target = sandbox.root + name
target.rmtree if target.exist?
downloader = Config.instance.downloader(target, params)
downloader.download
store_podspec(sandbox, target + "#{name}.podspec")
sandbox.store_pre_downloaded_pod(name)
if downloader.options_specific?
source = params
else
source = downloader.checkout_options
end
sandbox.store_checkout_source(name, source)
end
end
# Stores the podspec in the sandbox and marks it as from an external
# source.
#
# @param [Sandbox] sandbox
# The sandbox where the specification should be stored.
#
# @param [Pathname, String] spec
# The path of the specification or its contents.
#
# @note All the concrete implementations of #{fetch} should invoke this
# method.
#
# @note The sandbox ensures that the podspec exists and that the names
# match.
#
# @return [void]
#
def store_podspec(sandbox, spec)
sandbox.store_podspec(name, spec, true)
end
end
#-------------------------------------------------------------------------#
# Provides support for fetching a specification file from a Git remote.
#
# Supports all the options of the downloader (is similar to the git key of
# `source` attribute of a specification).
#
# @note The podspec must be in the root of the repository and should have a
# name matching the one of the dependency.
#
class GitSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
pre_download(sandbox)
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:git]}`".tap do |description|
description << ", commit `#{params[:commit]}`" if params[:commit]
description << ", branch `#{params[:branch]}`" if params[:branch]
description << ", tag `#{params[:tag]}`" if params[:tag]
end
end
end
#-------------------------------------------------------------------------#
# Provides support for fetching a specification file from a SVN source
# remote.
#
# Supports all the options of the downloader (is similar to the git key of
# `source` attribute of a specification).
#
# @note The podspec must be in the root of the repository and should have a
# name matching the one of the dependency.
#
class SvnSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
pre_download(sandbox)
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:svn]}`".tap do |description|
description << ", folder `#{params[:folder]}`" if params[:folder]
description << ", tag `#{params[:tag]}`" if params[:tag]
description << ", revision `#{params[:revision]}`" if params[:revision]
end
end
end
#-------------------------------------------------------------------------#
# Provides support for fetching a specification file from a Mercurial
# source remote.
#
# Supports all the options of the downloader (is similar to the git key of
# `source` attribute of a specification).
#
# @note The podspec must be in the root of the repository and should have a
# name matching the one of the dependency.
#
class MercurialSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
pre_download(sandbox)
end
# @see AbstractExternalSource#description
# @return [Class]
#
def description
"from `#{params[:hg]}`".tap do |description|
description << ", revision `#{params[:revision]}`" if params[:revision]
def self.concrete_class_from_params(params)
if params.key?(:podspec)
PodspecSource
elsif params.key?(:path)
PathSource
elsif params.key?(:local)
UI.warn "The `:local` option of the Podfile has been " \
"renamed to `:path` and it is deprecated."
PathSource
elsif Downloader.strategy_from_options(params)
DownloaderSource
end
end
end
#-------------------------------------------------------------------------#
# Provides support for fetching a specification file from a Bazaar
# source remote.
#
# Supports all the options of the downloader (is similar to the git key of
# `source` attribute of a specification).
#
# @note The podspec must be in the root of the repository and should have a
# name matching the one of the dependency.
#
class BazaarSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
pre_download(sandbox)
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:bzr]}`".tap do |description|
description << ", tag `#{params[:tag]}`" if params[:tag]
description << ", revision `#{params[:revision]}`" if params[:revision]
end
end
end
#-------------------------------------------------------------------------#
# Provides support for fetching a specification file from an URL. Can be
# http, file, etc.
#
class PodspecSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
require 'open-uri'
open(podspec_uri) { |io| store_podspec(sandbox, io.read) }
end
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:podspec]}`"
end
#--------------------------------------#
private
# @!group Helpers
# @return [String] The uri of the podspec appending the name of the file
# and expanding it if necessary.
#
# @note If the declared path is expanded only if the represents a path
# relative to the file system.
#
def podspec_uri
declared_path = params[:podspec].to_s
if declared_path.match(%r{^.+://})
declared_path
else
path_with_ext = File.extname(declared_path) == '.podspec' ? declared_path : "#{declared_path}/#{name}.podspec"
podfile_dir = File.dirname(podfile_path || '')
absolute_path = File.expand_path(path_with_ext, podfile_dir)
absolute_path
end
end
end
#-------------------------------------------------------------------------#
# Provides support for fetching a specification file from a path local to
# the machine running the installation.
#
# Works with the {LocalPod::LocalSourcedPod} class.
#
class PathSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
podspec = podspec_path
store_podspec(sandbox, podspec)
sandbox.store_local_path(name, podspec.dirname)
end
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:path] || params[:local]}`"
end
#--------------------------------------#
private
# @!group Helpers
# @return [Pathname] the path of the podspec.
#
def podspec_path
declared_path = (params[:path] || params[:local]).to_s
path_with_ext = File.extname(declared_path) == '.podspec' ? declared_path : "#{declared_path}/#{name}.podspec"
podfile_dir = File.dirname(podfile_path || '')
absolute_path = File.expand_path(path_with_ext, podfile_dir)
pathname = Pathname.new(absolute_path)
unless pathname.exist?
raise Informative, "No podspec found for `#{name}` in `#{params[:local]}`"
end
pathname
end
end
#-------------------------------------------------------------------------#
end
end
module Pod
module ExternalSources
# Abstract class that defines the common behaviour of external sources.
#
class AbstractExternalSource
# @return [String] the name of the Pod described by this external source.
#
attr_reader :name
# @return [Hash{Symbol => String}] the hash representation of the
# external source.
#
attr_reader :params
# @return [String] the path where the podfile is defined to resolve
# relative paths.
#
attr_reader :podfile_path
# @param [String] name @see name
# @param [Hash] params @see params
# @param [String] podfile_path @see podfile_path
#
def initialize(name, params, podfile_path)
@name = name
@params = params
@podfile_path = podfile_path
end
# @return [Bool] whether an external source source is equal to another
# according to the {#name} and to the {#params}.
#
def ==(other)
return false if other.nil?
name == other.name && params == other.params
end
public
# @!group Subclasses hooks
# Fetches the external source from the remote according to the params.
#
# @param [Sandbox] sandbox
# the sandbox where the specification should be stored.
#
# @return [void]
#
def fetch(sandbox)
raise "Abstract method"
end
# @return [String] a string representation of the source suitable for UI.
#
def description
raise "Abstract method"
end
protected
# @return [String] The uri of the podspec appending the name of the file
# and expanding it if necessary.
#
# @note If the declared path is expanded only if the represents a path
# relative to the file system.
#
def normalized_podspec_path(declared_path)
extension = File.extname(declared_path)
if extension == '.podspec' || extension == '.json'
path_with_ext = declared_path
else
path_with_ext = "#{declared_path}/#{name}.podspec"
end
podfile_dir = File.dirname(podfile_path || '')
File.expand_path(path_with_ext, podfile_dir)
end
private
# @! Subclasses helpers
# Pre-downloads a Pod passing the options to the downloader and informing
# the sandbox.
#
# @param [Sandbox] sandbox
# The sandbox where the Pod should be downloaded.
#
# @note To prevent a double download of the repository the pod is
# marked as pre-downloaded indicating to the installer that only
# clean operations are needed.
#
# @todo The downloader configuration is the same of the
# #{PodSourceInstaller} and it needs to be kept in sync.
#
# @return [void]
#
def pre_download(sandbox)
title = "Pre-downloading: `#{name}` #{description}"
UI.titled_section(title, { :verbose_prefix => "-> " }) do
target = sandbox.root + name
target.rmtree if target.exist?
downloader = Config.instance.downloader(target, params)
downloader.download
store_podspec(sandbox, target + "#{name}.podspec")
sandbox.store_pre_downloaded_pod(name)
if downloader.options_specific?
source = params
else
source = downloader.checkout_options
end
sandbox.store_checkout_source(name, source)
end
end
# Stores the podspec in the sandbox and marks it as from an external
# source.
#
# @param [Sandbox] sandbox
# The sandbox where the specification should be stored.
#
# @param [Pathname, String] spec
# The path of the specification or its contents.
#
# @note All the concrete implementations of #{fetch} should invoke this
# method.
#
# @note The sandbox ensures that the podspec exists and that the names
# match.
#
# @return [void]
#
def store_podspec(sandbox, spec, json = false)
sandbox.store_podspec(name, spec, true, json)
end
end
end
end
module Pod
module ExternalSources
# Provides support for fetching a specification file from a source handled
# by the downloader. Supports all the options of the downloader
#
# @note The podspec must be in the root of the repository and should have a
# name matching the one of the dependency.
#
class DownloaderSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
pre_download(sandbox)
end
# @see AbstractExternalSource#description
#
def description
strategy = Downloader.strategy_from_options(params)
options = params.dup
url = options.delete(strategy)
result = "from `#{url}`"
options.each do |key, value|
result << ", #{key} `#{value}`"
end
result
end
end
end
end
module Pod
module ExternalSources
# Provides support for fetching a specification file from a path local to
# the machine running the installation.
#
# Works with the {LocalPod::LocalSourcedPod} class.
#
class PathSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
title = "Fetching podspec for `#{name}` #{description}"
UI.titled_section(title, { :verbose_prefix => "-> " }) do
podspec = podspec_path
unless podspec.exist?
raise Informative, "No podspec found for `#{name}` in " \
"`#{declared_path}`"
end
store_podspec(sandbox, podspec)
is_absolute = absolute?(declared_path)
sandbox.store_local_path(name, podspec.dirname, is_absolute)
end
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:path] || params[:local]}`"
end
private
# @!group Helpers
# @return [String] The path as declared by the user.
#
def declared_path
result = params[:path] || params[:local]
result.to_s if result
end
# @return [Pathname] The absolute path of the podspec.
#
def podspec_path
Pathname(normalized_podspec_path(declared_path))
end
# @return [Bool]
#
def absolute?(path)
Pathname(path).absolute? || path.to_s.start_with?('~')
end
end
end
end
module Pod
module ExternalSources
# Provides support for fetching a specification file from an URL. Can be
# http, file, etc.
#
class PodspecSource < AbstractExternalSource
# @see AbstractExternalSource#fetch
#
def fetch(sandbox)
title = "Fetching podspec for `#{name}` #{description}"
UI.titled_section(title, { :verbose_prefix => "-> " }) do
is_json = podspec_uri.split('.').last == 'json'
require 'open-uri'
open(podspec_uri) { |io| store_podspec(sandbox, io.read, is_json) }
end
end
# @see AbstractExternalSource#description
#
def description
"from `#{params[:podspec]}`"
end
private
# @!group Helpers
# @return [String] The uri of the podspec appending the name of the file
# and expanding it if necessary.
#
# @note If the declared path is expanded only if the represents a path
# relative to the file system.
#
def podspec_uri
declared_path = params[:podspec].to_s
if declared_path.match(%r{^.+://})
declared_path
else
normalized_podspec_path(declared_path)
end
end
end
end
end
module Pod
# The version of the cocoapods command line tool.
#
VERSION = '0.29.0' unless defined? Pod::VERSION
VERSION = '0.33.1' unless defined? Pod::VERSION
end
......@@ -40,9 +40,12 @@ module Pod
# added to the top of the prefix header. For OS X `Cocoa/Cocoa.h`
# is imported.
#
# @note Only unique prefix_header_contents are added to the prefix header.
#
# @return [String]
#
# @todo Subspecs can specify prefix header information too.
# @todo Check to see if we have a similar duplication issue with file_accessor.prefix_header.
#
def generate
result = "#ifdef __OBJC__\n"
......@@ -53,12 +56,18 @@ module Pod
result << %|\n#import "#{import}"|
end
file_accessors.each do |file_accessor|
unique_prefix_header_contents = file_accessors.collect do |file_accessor|
file_accessor.spec_consumer.prefix_header_contents
end.compact.uniq
result << "\n"
if prefix_header_contents = file_accessor.spec_consumer.prefix_header_contents
unique_prefix_header_contents.each do |prefix_header_contents|
result << prefix_header_contents
result << "\n"
end
file_accessors.each do |file_accessor|
if prefix_header = file_accessor.prefix_header
result << Pathname(prefix_header).read
end
......
......@@ -64,11 +64,12 @@ module Pod
@lockfile = lockfile
end
# @return [Bool] Whether the installer is in update mode. In update mode
# the contents of the Lockfile are not taken into account for
# deciding what Pods to install.
# @return [Hash, Boolean, nil] Pods that have been requested to be
# updated or true if all Pods should be updated.
# If all Pods should been updated the contents of the Lockfile are
# not taken into account for deciding what Pods to install.
#
attr_accessor :update_mode
attr_accessor :update
# Installs the Pods.
#
......@@ -89,6 +90,7 @@ module Pod
download_dependencies
generate_pods_project
integrate_user_project if config.integrate_targets?
perform_post_install_actions
end
def resolve_dependencies
......@@ -164,13 +166,14 @@ module Pod
#
def analyze
if lockfile && lockfile.cocoapods_version > Version.new(VERSION)
STDERR.puts '[!] The version of CocoaPods used to generate the lockfile is '\
'higher than the version of the current executable. Incompatibility ' \
'issues may arise.'.yellow
STDERR.puts '[!] The version of CocoaPods used to generate ' \
"the lockfile (#{lockfile.cocoapods_version}) is "\
"higher than the version of the current executable (#{VERSION}). " \
'Incompatibility issues may arise.'.yellow
end
analyzer = Analyzer.new(sandbox, podfile, lockfile)
analyzer.update_mode = update_mode
analyzer.update = update
@analysis_result = analyzer.analyze
@aggregate_targets = analyzer.result.targets
end
......@@ -249,7 +252,13 @@ module Pod
title_options = { :verbose_prefix => "-> ".green }
root_specs.sort_by(&:name).each do |spec|
if pods_to_install.include?(spec.name)
UI.titled_section("Installing #{spec}".green, title_options) do
if sandbox_state.changed.include?(spec.name) && sandbox.manifest
previous = sandbox.manifest.version(spec.name)
title = "Installing #{spec.name} #{spec.version} (was #{previous})"
else
title = "Installing #{spec}"
end
UI.titled_section(title.green, title_options) do
install_source_of_pod(spec.name)
end
else
......@@ -293,6 +302,32 @@ module Pod
end
end
# Performs any post-installation actions
#
# @return [void]
#
def perform_post_install_actions
warn_for_deprecations
end
# Prints a warning for any pods that are deprecated
#
# @return [void]
#
def warn_for_deprecations
deprecated_pods = root_specs.select do |spec|
spec.deprecated || spec.deprecated_in_favor_of
end
deprecated_pods.each do |spec|
if spec.deprecated_in_favor_of
UI.warn "#{spec.name} has been deprecated in " \
"favor of #{spec.deprecated_in_favor_of}"
else
UI.warn "#{spec.name} has been deprecated"
end
end
end
# Creates the Pods project from scratch if it doesn't exists.
#
# @return [void]
......@@ -309,9 +344,10 @@ module Pod
pod_names = pod_targets.map(&:pod_name).uniq
pod_names.each do |pod_name|
path = sandbox.pod_dir(pod_name)
local = sandbox.local?(pod_name)
@pods_project.add_pod_group(pod_name, path, local)
path = sandbox.pod_dir(pod_name)
was_absolute = sandbox.local_path_was_absolute?(pod_name)
@pods_project.add_pod_group(pod_name, path, local, was_absolute)
end
if config.podfile_path
......@@ -458,42 +494,11 @@ module Pod
#
def run_pre_install_hooks
UI.message "- Running pre install hooks" do
analysis_result.specifications.each do |spec|
executed = false
libraries_using_spec(spec).each do |lib|
lib_representation = library_rep(lib)
executed ||= run_spec_pre_install_hook(spec, lib_representation)
end
UI.message "- #{spec.name}" if executed
end
executed = run_podfile_pre_install_hook
UI.message "- Podfile" if executed
end
end
# Runs the pre install hook of the given specification with the given
# library representation.
#
# @param [Specification] spec
# The spec for which the pre install hook should be run.
#
# @param [Hooks::LibraryRepresentation] lib_representation
# The library representation to be passed as an argument to the
# hook.
#
# @raise Raises an informative if the hooks raises.
#
# @return [Bool] Whether the hook was run.
#
def run_spec_pre_install_hook(spec, lib_representation)
spec.pre_install!(pod_rep(spec.root.name), lib_representation)
rescue => e
raise Informative, "An error occurred while processing the pre-install " \
"hook of #{spec}." \
"\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
end
# Runs the pre install hook of the Podfile
#
# @raise Raises an informative if the hooks raises.
......@@ -517,42 +522,11 @@ module Pod
#
def run_post_install_hooks
UI.message "- Running post install hooks" do
analysis_result.specifications.each do |spec|
executed = false
libraries_using_spec(spec).each do |lib|
lib_representation = library_rep(lib)
executed ||= run_spec_post_install_hook(spec, lib_representation)
end
UI.message "- #{spec.name}" if executed
end
executed = run_podfile_post_install_hook
UI.message "- Podfile" if executed
end
end
# Runs the post install hook of the given specification with the given
# library representation.
#
# @param [Specification] spec
# The spec for which the post install hook should be run.
#
# @param [Hooks::LibraryRepresentation] lib_representation
# The library representation to be passed as an argument to the
# hook.
#
# @raise Raises an informative if the hooks raises.
#
# @return [Bool] Whether the hook was run.
#
def run_spec_post_install_hook(spec, lib_representation)
spec.post_install!(lib_representation)
rescue => e
raise Informative, "An error occurred while processing the post-install " \
"hook of #{spec}." \
"\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
end
# Runs the post install hook of the Podfile
#
# @raise Raises an informative if the hooks raises.
......
......@@ -33,7 +33,7 @@ module Pod
@podfile = podfile
@lockfile = lockfile
@update_mode = false
@update = false
@allow_pre_downloads = true
@archs_by_target_def = {}
end
......@@ -91,11 +91,30 @@ module Pod
# @!group Configuration
# @return [Hash, Boolean, nil] Pods that have been requested to be
# updated or true if all Pods should be updated
#
attr_accessor :update
# @return [Bool] Whether the version of the dependencies which did non
# change in the Podfile should be locked.
#
attr_accessor :update_mode
alias_method :update_mode?, :update_mode
def update_mode?
!!update
end
# @return [Symbol] Whether and how the dependencies in the Podfile
# should be updated.
#
def update_mode
if !update
:none
elsif update == true
:all
elsif update[:pods] != nil
:selected
end
end
# @return [Bool] Whether the analysis allows pre-downloads and thus
# modifications to the sandbox.
......@@ -219,10 +238,15 @@ module Pod
# that prevent the resolver to update a Pod.
#
def generate_version_locking_dependencies
if update_mode?
if update_mode == :all
[]
else
result.podfile_state.unchanged.map do |pod|
locking_pods = result.podfile_state.unchanged
if update_mode == :selected
# If selected Pods should been updated, filter them out of the list
locking_pods = locking_pods.select { |pod| !update[:pods].include?(pod) }
end
locking_pods.map do |pod|
lockfile.dependency_to_lock_pod_named(pod)
end
end
......@@ -252,10 +276,14 @@ module Pod
deps_to_fetch = []
deps_to_fetch_if_needed = []
deps_with_external_source = podfile.dependencies.select { |dep| dep.external_source }
if update_mode?
if update_mode == :all
deps_to_fetch = deps_with_external_source
else
pods_to_fetch = result.podfile_state.added + result.podfile_state.changed
if update_mode == :selected
pods_to_fetch += update[:pods]
end
deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch.include?(dep.root_name) }
deps_to_fetch_if_needed = deps_with_external_source.select { |dep| result.podfile_state.unchanged.include?(dep.root_name) }
deps_to_fetch += deps_to_fetch_if_needed.select { |dep| sandbox.specification(dep.root_name).nil? || !dep.external_source[:local].nil? || !dep.external_source[:path].nil? }
......@@ -316,7 +344,7 @@ module Pod
def generate_sandbox_state
sandbox_state = nil
UI.section "Comparing resolved specification to the sandbox manifest" do
sandbox_analyzer = SandboxAnalyzer.new(sandbox, result.specifications, update_mode, lockfile)
sandbox_analyzer = SandboxAnalyzer.new(sandbox, result.specifications, update_mode?, lockfile)
sandbox_state = sandbox_analyzer.analyze
sandbox_state.print
end
......
......@@ -63,6 +63,12 @@ module Pod
def install!
download_source unless predownloaded? || local?
run_prepare_command
rescue Informative
raise
rescue Object => e
UI.notice("Error installing #{root_spec.name}")
clean!
raise
end
# Cleans the installations if appropriate.
......@@ -95,8 +101,18 @@ module Pod
def download_source
root.rmtree if root.exist?
if head_pod?
begin
downloader.download_head
@specific_source = downloader.checkout_options
rescue RuntimeError => e
if e.message == 'Abstract method'
raise Informative, "The pod '" + root_spec.name + "' does not " +
"support the :head option, as it uses a " + downloader.name +
" source. Remove that option to use this pod."
else
raise
end
end
else
downloader.download
unless downloader.options_specific?
......@@ -114,12 +130,17 @@ module Pod
# Runs the prepare command bash script of the spec.
#
# @note Unsets the `CDPATH` env variable before running the
# shell script to avoid issues with relative paths
# (issue #1694).
#
# @return [void]
#
def run_prepare_command
return unless root_spec.prepare_command
UI.section(" > Running prepare command", '', 1) do
Dir.chdir(root) do
ENV.delete('CDPATH')
prepare_command = root_spec.prepare_command.strip_heredoc.chomp
full_command = "\nset -e\n" + prepare_command
bash!(full_command)
......
......@@ -15,7 +15,6 @@ module Pod
add_target
add_files_to_build_phases
add_resources_bundle_targets
# create_suport_files_group
create_xcconfig_file
create_prefix_header
create_dummy_source
......
......@@ -81,21 +81,22 @@ module Pod
#
def create_workspace
all_projects = user_project_paths.sort.push(sandbox.project_path).uniq
projpaths = all_projects.map do |path|
path.relative_path_from(workspace_path.dirname).to_s
file_references = all_projects.map do |path|
relative_path = path.relative_path_from(workspace_path.dirname).to_s
Xcodeproj::Workspace::FileReference.new(relative_path, 'group')
end
if workspace_path.exist?
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
new_projpaths = projpaths - workspace.projpaths
unless new_projpaths.empty?
workspace.projpaths.concat(new_projpaths)
new_file_references = file_references - workspace.file_references
unless new_file_references.empty?
workspace.file_references.concat(new_file_references)
workspace.save_as(workspace_path)
end
else
UI.notice "From now on use `#{workspace_path.basename}`."
workspace = Xcodeproj::Workspace.new(*projpaths)
workspace = Xcodeproj::Workspace.new(*file_references)
workspace.save_as(workspace_path)
end
end
......
......@@ -69,6 +69,7 @@ module Pod
@head_pods = []
@checkout_sources = {}
@development_pods = {}
@pods_with_absolute_path = []
end
# @return [Lockfile] the manifest which contains the information about the
......@@ -159,6 +160,16 @@ module Pod
end
end
# Returns true if the path as originally specified was absolute.
#
# @param [String] name
#
# @return [Bool] true if originally absolute
#
def local_path_was_absolute?(name)
@pods_with_absolute_path.include? name
end
# @return [Pathname] the directory where to store the documentation.
#
def documentation_dir
......@@ -180,7 +191,8 @@ module Pod
#
def specification(name)
if file = specification_path(name)
Specification.from_file(file)
original_path = development_pods[name]
Dir.chdir(original_path || Dir.pwd) { Specification.from_file(file) }
end
end
......@@ -206,7 +218,16 @@ module Pod
#
def specification_path(name)
path = specifications_dir + "#{name}.podspec"
path.exist? ? path : nil
if path.exist?
path
else
path = specifications_dir + "#{name}.podspec.json"
if path.exist?
path
else
nil
end
end
end
# Stores a specification in the `Local Podspecs` folder.
......@@ -221,8 +242,9 @@ module Pod
# @todo Store all the specifications (including those not originating
# from external sources) so users can check them.
#
def store_podspec(name, podspec, external_source = false)
output_path = specifications_dir(external_source) + "#{name}.podspec"
def store_podspec(name, podspec, external_source = false, json = false)
file_name = json ? "#{name}.podspec.json" : "#{name}.podspec"
output_path = specifications_dir(external_source) + file_name
output_path.dirname.mkpath
if podspec.is_a?(String)
output_path.open('w') { |f| f.puts(podspec) }
......@@ -232,11 +254,15 @@ module Pod
end
FileUtils.copy(podspec, output_path)
end
Dir.chdir(podspec.is_a?(Pathname) ? File.dirname(podspec) : Dir.pwd) do
spec = Specification.from_file(output_path)
unless spec.name == name
raise Informative, "The name of the given podspec `#{spec.name}` doesn't match the expected one `#{name}`"
end
end
end
#-------------------------------------------------------------------------#
......@@ -338,11 +364,15 @@ module Pod
# @param [#to_s] path
# The local path where the Pod is stored.
#
# @param [Bool] was_absolute
# True if the specified local path was absolute.
#
# @return [void]
#
def store_local_path(name, path)
def store_local_path(name, path, was_absolute = false)
root_name = Specification.root_name(name)
development_pods[root_name] = path.to_s
@pods_with_absolute_path << root_name if was_absolute
end
# @return [Hash{String=>String}] The path of the Pods with a local source
......
......@@ -152,8 +152,13 @@ module Pod
sources.each do |source|
UI.section "Updating spec repo `#{source.name}`" do
Dir.chdir(source.data_provider.repo) do
output = git!("pull")
begin
output = git!("pull --ff-only")
UI.puts output if show_output && !config.verbose?
rescue Informative => e
raise Informative, 'An error occurred while performing ' \
"`git pull` on repo `#{source.name}`.\n" + e.message
end
end
check_version_information(source.data_provider.repo)
end
......@@ -201,12 +206,16 @@ module Pod
min, max = versions['min'], versions['max']
version_msg = ( min == max ) ? min : "#{min} - #{max}"
raise Informative, "The `#{dir.basename}` repo requires " \
"CocoaPods #{version_msg}\n".red +
"CocoaPods #{version_msg} (currently using #{Pod::VERSION})\n".red +
"Update CocoaPods, or checkout the appropriate tag in the repo."
end
needs_sudo = path_writable?(__FILE__)
if config.new_version_message? && cocoapods_update?(versions)
UI.puts "\nCocoaPods #{versions['last']} is available.\n".green
UI.puts "\nCocoaPods #{versions['last']} is available.\n" \
"To update use: #{needs_sudo ? 'sudo ' : ''}" \
'gem install cocoapods\n'.green
end
end
......@@ -258,7 +267,16 @@ module Pod
def version_information(dir)
require 'yaml'
yaml_file = dir + 'CocoaPods-version.yml'
yaml_file.exist? ? YAML.load_file(yaml_file) : {}
return {} unless yaml_file.exist?
begin
yaml = Pathname.new(yaml_file).read
YAMLHelper.load(yaml)
rescue Informative => e
raise Informative, "There was an error reading '#{yaml_file}'.\n" \
'Please consult http://blog.cocoapods.org/' \
'Repairing-Our-Broken-Specs-Repository/ ' \
'for more information.'
end
end
public
......@@ -283,6 +301,12 @@ module Pod
#-----------------------------------------------------------------------#
private
def path_writable?(path)
Pathname(path).dirname.writable?
end
end
end
end
......
......@@ -158,8 +158,8 @@ module Pod
# Prints the textual representation of a given set.
#
def pod(set, mode = :normal, statistics_provider = nil)
if mode == :name
puts_indented set.name
if mode == :name_and_version
puts_indented "#{set.name} #{set.versions.first.version}"
else
pod = Specification::Set::Presenter.new(set, statistics_provider)
title("\n-> #{pod.name} (#{pod.version})".green, '', 1) do
......@@ -184,10 +184,10 @@ module Pod
# Prints a message with a label.
#
def labeled(label, value)
def labeled(label, value, justification = 16)
if value
''.tap do |t|
t << " - #{label}:".ljust(16)
t << " - #{label}:".ljust(justification)
if value.is_a?(Array)
separator = "\n - "
puts_indented t << separator << value.join(separator)
......
......@@ -45,7 +45,7 @@ Repositories : #{repo_information.join("\n ")}
#{'[!] Oh no, an error occurred.'.red}
#{error_from_podfile(exception)}
#{'Search for existing github issues similar to yours:'.yellow}
#{"https://github.com/CocoaPods/CocoaPods/search?q=#{CGI.escape(exception.message)}&type=Issues"}
#{issues_url(exception)}
#{'If none exists, create a ticket, with the template displayed above, on:'.yellow}
https://github.com/CocoaPods/CocoaPods/issues/new
......@@ -57,6 +57,10 @@ EOS
private
def pathless_exception_message(message)
message.gsub(/- \(.*\):/, '-')
end
def markdown_podfile
return '' unless Config.instance.podfile_path && Config.instance.podfile_path.exist?
<<-EOS
......@@ -75,6 +79,16 @@ EOS
end
end
def remove_color(string)
string.gsub(/\e\[(\d+)m/, '')
end
def issues_url(exception)
message = remove_color(pathless_exception_message(exception.message))
'https://github.com/CocoaPods/CocoaPods/search?q=' \
"#{CGI.escape(message)}&type=Issues"
end
def host_information
product, version, build =`sw_vers`.strip.split("\n").map { |line| line.split(":").last.strip }
"#{product} #{version} (#{build})"
......
......@@ -196,6 +196,12 @@ module Pod
# Perform analysis for a given spec (or subspec)
#
def perform_extensive_analysis(spec)
validate_homepage(spec)
validate_screenshots(spec)
validate_social_media_url(spec)
validate_documentation_url(spec)
validate_docset_url(spec)
spec.available_platforms.each do |platform|
UI.message "\n\n#{spec} - Analyzing on #{platform} platform.".green.reversed
@consumer = spec.consumer(platform)
......@@ -208,7 +214,7 @@ module Pod
perform_extensive_subspec_analysis(spec) unless @no_subspecs
end
# Recurively perform the extensive analysis on all subspecs
# Recursively perform the extensive analysis on all subspecs
#
def perform_extensive_subspec_analysis(spec)
spec.subspecs.each do |subspec|
......@@ -220,6 +226,57 @@ module Pod
attr_accessor :consumer
attr_accessor :subspec_name
# Performs validation of a URL
#
def validate_url(url)
resp = Pod::HTTP::validate_url(url)
if !resp
warning "There was a problem validating the URL #{url}."
elsif !resp.success?
warning "The URL (#{url}) is not reachable."
end
resp
end
# Performs validations related to the `homepage` attribute.
#
def validate_homepage(spec)
if spec.homepage
validate_url(spec.homepage)
end
end
# Performs validation related to the `screenshots` attribute.
#
def validate_screenshots(spec)
spec.screenshots.compact.each do |screenshot|
request = validate_url(screenshot)
if request && !(request.headers['content-type'] && request.headers['content-type'].first =~ /image\/.*/i)
warning "The screenshot #{screenshot} is not a valid image."
end
end
end
# Performs validations related to the `social_media_url` attribute.
#
def validate_social_media_url(spec)
validate_url(spec.social_media_url) if spec.social_media_url
end
# Performs validations related to the `documentation_url` attribute.
#
def validate_documentation_url(spec)
validate_url(spec.documentation_url) if spec.documentation_url
end
# Performs validations related to the `docset_url` attribute.
#
def validate_docset_url(spec)
validate_url(spec.docset_url) if spec.docset_url
end
def setup_validation_environment
validation_dir.rmtree if validation_dir.exist?
validation_dir.mkpath
......@@ -294,10 +351,12 @@ module Pod
end
end
if consumer.spec.root?
unless file_accessor.license || spec.license && ( spec.license[:type] == 'Public Domain' || spec.license[:text] )
warning "Unable to find a license file"
end
end
end
#-------------------------------------------------------------------------#
......@@ -392,9 +451,10 @@ module Pod
end
# @return [String] Executes xcodebuild in the current working directory and
# returns its output (bot STDOUT and STDERR).
# returns its output (both STDOUT and STDERR).
#
def xcodebuild
UI.puts 'xcodebuild clean build -target Pods' if config.verbose?
`xcodebuild clean build -target Pods 2>&1`
end
......
Subproject commit 05902614470a36022b0eb7854641191fd3971254
Subproject commit 9ff0ddd87c25f7357a70e8863cef47b0e2557eca
This is a Bazaar control directory.
Do not change any files in this directory.
See http://bazaar.canonical.com/ for more information about Bazaar.
Bazaar-NG meta directory, format 1
Bazaar Branch Format 7 (needs bzr 1.6)
2 fred@sharpnoodles.com-20131030202140-gg5dfrrtaotfxlrh
Bazaar Working Tree Format 6 (bzr 1.14)
Bazaar repository format 2a (needs bzr 1.16 or later)
B+Tree Graph Index 2
node_ref_lists=1
key_elements=1
len=1
row_lengths=1
xQ
;0޺tK-R4n?'oCwK;l-W.6l
"ǰ^c:BMF@,B
\ No newline at end of file
B+Tree Graph Index 2
node_ref_lists=0
key_elements=1
len=0
row_lengths=
B+Tree Graph Index 2
node_ref_lists=1
key_elements=2
len=3
row_lengths=1
xM0@a֜ Lg ԅ71P,ȏ-+M W'ܦ5CH>xi& ("ükA boax{oļ#PB][а^IR`2
4i,FE;;t
"tJ57sL :*7}v e
\ No newline at end of file
B+Tree Graph Index 2
node_ref_lists=0
key_elements=1
len=1
row_lengths=1
x PLZ
8'@8x0ы&V|6Hcr7eyhZCbr"&s?-
\ No newline at end of file
B+Tree Graph Index 2
node_ref_lists=0
key_elements=1
len=0
row_lengths=
Pod::Spec.new do |s|
s.name = "BazaarSource"
s.version = "0.0.1"
s.summary = "A short description of BazaarSource."
s.homepage = "http://EXAMPLE/BazaarSource"
s.license = 'MIT (example)'
s.author = { "Fred McCann" => "fred@sharpnoodles.com" }
s.source = { :git => "http://EXAMPLE/BazaarSource.git", :tag => "0.0.1" }
s.source_files = 'Classes', 'Classes/**/*.{h,m}'
end
Subproject commit 90e5fbce17d66e5341f105c1eb26133a01686838
Subproject commit 65a8282c0b5a6f84bc6266d73bbe7475ef75659d
Subproject commit 287a78804972c1c4ce41d9e2771e4beb63764a16
[ui]
username = Eloy Duran <eloy.de.enige@gmail.com>
Removed comments.
\ No newline at end of file
data/MercurialSource.podspec.i
data/README.i
1 3d2759856083e6dbb5b5d0b702aa625b5b21a10a
Pod::Spec.new do |s|
s.name = "MercurialSource"
s.version = "0.0.1"
s.summary = "A short description of MercurialSource."
s.homepage = "http://EXAMPLE/MercurialSource"
s.license = 'MIT (example)'
s.author = { "Dan Cutting" => "dcutting@gmail.com" }
s.source = { :git => "http://EXAMPLE/MercurialSource.git", :tag => "0.0.1" }
s.source_files = 'Classes', 'Classes/**/*.{h,m}'
end
Subproject commit ee564d9da8878957e7b77cac987d9601eb04eca5
Subproject commit b0f4e85738f1f911e32e2914b39e9acdce7c7ed9
......@@ -18,11 +18,4 @@ Pod::Spec.new do |s|
:file => 'LICENSE',
:text => 'Permission is hereby granted ...'
}
s.documentation = {
:html => 'http://banana-corp.local/banana-lib/docs.html',
:appledoc => [
'--project-company', 'Banana Corp',
'--company-id', 'com.banana',
]
}
end
This is a Subversion repository; use the 'svnadmin' tool to examine
it. Do not add, delete, or modify files here unless you know how
to avoid corrupting the repository.
Visit http://subversion.tigris.org/ for more information.
### This file is an example authorization file for svnserve.
### Its format is identical to that of mod_authz_svn authorization
### files.
### As shown below each section defines authorizations for the path and
### (optional) repository specified by the section name.
### The authorizations follow. An authorization line can refer to:
### - a single user,
### - a group of users defined in a special [groups] section,
### - an alias defined in a special [aliases] section,
### - all authenticated users, using the '$authenticated' token,
### - only anonymous users, using the '$anonymous' token,
### - anyone, using the '*' wildcard.
###
### A match can be inverted by prefixing the rule with '~'. Rules can
### grant read ('r') access, read-write ('rw') access, or no access
### ('').
[aliases]
# joe = /C=XZ/ST=Dessert/L=Snake City/O=Snake Oil, Ltd./OU=Research Institute/CN=Joe Average
[groups]
# harry_and_sally = harry,sally
# harry_sally_and_joe = harry,sally,&joe
# [/foo/bar]
# harry = rw
# &joe = r
# * =
# [repository:/baz/fuz]
# @harry_and_sally = rw
# * = r
### This file is an example password file for svnserve.
### Its format is similar to that of svnserve.conf. As shown in the
### example below it contains one section labelled [users].
### The name and password for each user follow, one account per line.
[users]
# harry = harryssecret
# sally = sallyssecret
### This file controls the configuration of the svnserve daemon, if you
### use it to allow access to this repository. (If you only allow
### access through http: and/or file: URLs, then this file is
### irrelevant.)
### Visit http://subversion.tigris.org/ for more information.
[general]
### These options control access to the repository for unauthenticated
### and authenticated users. Valid values are "write", "read",
### and "none". The sample settings below are the defaults.
# anon-access = read
# auth-access = write
### The password-db option controls the location of the password
### database file. Unless you specify a path starting with a /,
### the file's location is relative to the directory containing
### this configuration file.
### If SASL is enabled (see below), this file will NOT be used.
### Uncomment the line below to use the default password file.
# password-db = passwd
### The authz-db option controls the location of the authorization
### rules for path-based access control. Unless you specify a path
### starting with a /, the file's location is relative to the the
### directory containing this file. If you don't specify an
### authz-db, no path-based access control is done.
### Uncomment the line below to use the default authorization file.
# authz-db = authz
### This option specifies the authentication realm of the repository.
### If two repositories have the same authentication realm, they should
### have the same password database, and vice versa. The default realm
### is repository's uuid.
# realm = My First Repository
[sasl]
### This option specifies whether you want to use the Cyrus SASL
### library for authentication. Default is false.
### This section will be ignored if svnserve is not built with Cyrus
### SASL support; to check, run 'svnserve --version' and look for a line
### reading 'Cyrus SASL authentication is available.'
# use-sasl = true
### These options specify the desired strength of the security layer
### that you want SASL to provide. 0 means no encryption, 1 means
### integrity-checking only, values larger than 1 are correlated
### to the effective key length for encryption (e.g. 128 means 128-bit
### encryption). The values below are the defaults.
# min-encryption = 0
# max-encryption = 256
### This file controls the configuration of the FSFS filesystem.
[memcached-servers]
### These options name memcached servers used to cache internal FSFS
### data. See http://www.danga.com/memcached/ for more information on
### memcached. To use memcached with FSFS, run one or more memcached
### servers, and specify each of them as an option like so:
# first-server = 127.0.0.1:11211
# remote-memcached = mymemcached.corp.example.com:11212
### The option name is ignored; the value is of the form HOST:PORT.
### memcached servers can be shared between multiple repositories;
### however, if you do this, you *must* ensure that repositories have
### distinct UUIDs and paths, or else cached data from one repository
### might be used by another accidentally. Note also that memcached has
### no authentication for reads or writes, so you must ensure that your
### memcached servers are only accessible by trusted users.
[caches]
### When a cache-related error occurs, normally Subversion ignores it
### and continues, logging an error if the server is appropriately
### configured (and ignoring it with file:// access). To make
### Subversion never ignore cache errors, uncomment this line.
# fail-stop = true
[rep-sharing]
### To conserve space, the filesystem can optionally avoid storing
### duplicate representations. This comes at a slight cost in performace,
### as maintaining a database of shared representations can increase
### commit times. The space savings are dependent upon the size of the
### repository, the number of objects it contains and the amount of
### duplication between them, usually a function of the branching and
### merging process.
###
### The following parameter enables rep-sharing in the repository. It can
### be switched on and off at will, but for best space-saving results
### should be enabled consistently over the life of the repository.
# enable-rep-sharing = false
K 8
svn:date
V 27
2011-11-18T22:35:00.555031Z
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T22:36:39.964845Z
K 7
svn:log
V 14
Initial commit
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:25:58.501852Z
K 7
svn:log
V 5
tag 1
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:26:30.617415Z
K 7
svn:log
V 12
unintersting
END
K 10
svn:author
V 3
lbm
K 8
svn:date
V 27
2012-12-03T12:33:18.707618Z
K 7
svn:log
V 24
Added SvnSource podspec
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T22:36:55.378137Z
K 7
svn:log
V 13
Second commit
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T22:38:20.653871Z
K 7
svn:log
V 10
add subdir
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:14:35.265756Z
K 7
svn:log
V 25
Add proper svn structure.
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:15:57.343475Z
K 7
svn:log
V 13
tag a version
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:17:01.810456Z
K 7
svn:log
V 11
tag version
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:17:17.488194Z
K 7
svn:log
V 14
tagged version
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:17:45.822304Z
K 7
svn:log
V 17
different version
END
K 10
svn:author
V 4
eloy
K 8
svn:date
V 27
2011-11-18T23:25:31.320366Z
K 7
svn:log
V 5
tag 1
END
PLAIN
END
ENDREP
id: 0.0.r0/17
type: dir
count: 0
text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e
cpath: /
17 107
id: 2-4.0-10.r10/0
type: dir
pred: 2-4.0.r9/324
count: 4
text: 9 240 71 71 7db699d699fb8e3f5f5b75577f7337af
cpath: /tags/tag-1
copyfrom: 9 /trunk
PLAIN
K 5
tag-1
V 18
dir 2-4.0-10.r10/0
K 14
tagged-version
V 18
dir 2-4.0-5.r7/275
END
ENDREP
id: 1-4.0.r10/242
type: dir
pred: 1-4.0.r7/508
count: 3
text: 10 147 82 82 710e98498b49659cab7ca978f7367558
cpath: /tags
copyroot: 0 /
PLAIN
K 4
tags
V 17
dir 1-4.0.r10/242
K 5
trunk
V 16
dir 2-4.0.r9/324
END
ENDREP
id: 0.0.r10/459
type: dir
pred: 0.0.r9/539
count: 10
text: 10 378 68 68 1350231ca49d269ba334f78f5ff82de4
cpath: /
copyroot: 0 /
2-4._0.t9-9 add-dir false false /tags/tag-1
9 /trunk
459 588
id: 0-1.0-4.r4/0
type: file
pred: 0-1.0.r2/46
count: 2
text: 2 0 26 14 6d2fd4056babc68a3df3615c6361a522 667b7b6d0bf794ffbca8584b60497be5fea181d2 1-1/_1
cpath: /trunk/README
copyfrom: 2 /README
id: 0-3.1-4.r4/194
type: dir
pred: 0-3.0.r3/246
count: 1
text: 3 198 35 35 92805725a0ad7291b2bb1c985a3b096f
cpath: /trunk/dir
copyfrom: 3 /dir
PLAIN
K 6
README
V 17
file 0-1.0-4.r4/0
K 3
dir
V 18
dir 0-3.1-4.r4/194
END
ENDREP
id: 2-4.0.r4/421
type: dir
count: 0
text: 4 338 70 70 1302e144785b1f29a75c4371550ef7a5
cpath: /trunk
copyroot: 0 /
id: 1-4.0.r4/537
type: dir
count: 0
cpath: /tags
copyroot: 0 /
PLAIN
K 4
tags
V 16
dir 1-4.0.r4/537
K 5
trunk
V 16
dir 2-4.0.r4/421
END
ENDREP
id: 0.0.r4/681
type: dir
pred: 0.0.r3/440
count: 4
text: 4 601 67 67 a93953eb22a6cfcfd64d6f59a1ba8149
cpath: /
copyroot: 0 /
0-1._0.t3-3 add-file false false /trunk/README
2 /README
0-3._1.t3-3 add-dir false false /trunk/dir
3 /dir
_2.0.t3-3 add-dir false false /trunk
0-1.0.r2/46 delete-file false false /README
0-3.0.r3/246 delete-dir false false /dir
_1.0.t3-3 add-dir false false /tags
681 807
id: 2-4.0-5.r5/0
type: dir
pred: 2-4.0.r4/421
count: 1
text: 4 338 70 70 1302e144785b1f29a75c4371550ef7a5
cpath: /tags/tagged-version
copyfrom: 4 /trunk
PLAIN
K 14
tagged-version
V 16
dir 2-4.0-5.r5/0
END
ENDREP
id: 1-4.0.r5/213
type: dir
pred: 1-4.0.r4/537
count: 1
text: 5 154 46 46 d4a9b3df1f7b22adffe8c0d351c5f033
cpath: /tags
copyroot: 0 /
PLAIN
K 4
tags
V 16
dir 1-4.0.r5/213
K 5
trunk
V 16
dir 2-4.0.r4/421
END
ENDREP
id: 0.0.r5/427
type: dir
pred: 0.0.r4/681
count: 5
text: 5 347 67 67 2c669630127913bd14bbb09849d4532f
cpath: /
copyroot: 0 /
2-4._0.t4-4 add-dir false false /tags/tagged-version
4 /trunk
427 553
id: 2-4.0-7.r7/0
type: dir
pred: 2-4.0.r6/333
count: 2
text: 6 249 71 71 f0c7d69bd9f7850eb2b1bf893a2cff76
cpath: /tags/tagged-version/trunk
copyfrom: 6 /trunk
PLAIN
K 6
README
V 17
file 0-1.0-4.r4/0
K 3
dir
V 18
dir 0-3.1-4.r4/194
K 5
trunk
V 16
dir 2-4.0-7.r7/0
END
ENDREP
id: 2-4.0-5.r7/275
type: dir
pred: 2-4.0-5.r5/0
count: 2
text: 7 160 102 102 9e281f2563f4b0d13b52c88c3756d088
cpath: /tags/tagged-version
copyroot: 5 /tags/tagged-version
PLAIN
K 14
tagged-version
V 18
dir 2-4.0-5.r7/275
END
ENDREP
id: 1-4.0.r7/508
type: dir
pred: 1-4.0.r5/213
count: 2
text: 7 447 48 48 5754f08c0e6de74d12ccd64c552d9385
cpath: /tags
copyroot: 0 /
PLAIN
K 4
tags
V 16
dir 1-4.0.r7/508
K 5
trunk
V 16
dir 2-4.0.r6/333
END
ENDREP
id: 0.0.r7/722
type: dir
pred: 0.0.r6/548
count: 7
text: 7 642 67 67 a4a2261a005434283c7cf5295d77ca6e
cpath: /
copyroot: 0 /
2-4._0.t6-6 add-dir false false /tags/tagged-version/trunk
6 /trunk
722 848
a66ec713-344f-4902-9a97-2b60e25f44bb
This file is not used by Subversion 1.3.x or later.
However, its existence is required for compatibility with
Subversion 1.2.x or earlier.
This file is not used by Subversion 1.3.x or later.
However, its existence is required for compatibility with
Subversion 1.2.x or earlier.
......@@ -5,8 +5,8 @@ module Pod
extend SpecHelper::Command
it "invokes the right command with --help flag" do
command = command('help', 'push')
command.send(:help_command).should.be.instance_of Pod::Command::Push
command = command('help', 'repo', 'push')
command.send(:help_command).should.be.instance_of Pod::Command::Repo::Push
lambda { command.run }.should.raise CLAide::Help
end
......@@ -15,7 +15,8 @@ module Pod
end
it "shows the right usage" do
Pod::Command::Help.arguments.should.equal '[COMMAND]'
args = [CLAide::Argument.new('COMMAND', false)]
Pod::Command::Help.arguments.should.equal args
end
end
......
......@@ -122,5 +122,27 @@ module Pod
end
end
it "saves xcode project file in Podfile if one was supplied" do
Dir.chdir(temporary_directory) do
Xcodeproj::Project.new(temporary_directory + 'test1.xcodeproj').save
Xcodeproj::Project.new(temporary_directory + 'Project.xcodeproj').save
run_command('init', 'Project.xcodeproj')
target_definition = config.podfile.target_definitions.values.first
target_definition.user_project_path.should == 'Project.xcodeproj'
end
end
it "doesn't save xcode project file in Podfile if one wasn't supplied" do
Dir.chdir(temporary_directory) do
Xcodeproj::Project.new(temporary_directory + 'Project.xcodeproj').save
run_command('init')
target_definition = config.podfile.target_definitions.values.first
target_definition.user_project_path.should == nil
end
end
end
end
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe Command::Lib::Create do
before do
@sut = Command::Lib::Create
end
it "complains if wrong parameters" do
lambda { run_command('lib', 'create') }.should.raise CLAide::Help
end
......@@ -9,12 +15,55 @@ module Pod
it "complains if pod name contains spaces" do
lambda { run_command('lib', 'create', 'Pod Name With Spaces') }.should.raise CLAide::Help
end
it "complains if pod name begins with a period" do
lambda { run_command('lib', 'create', '.HiddenPod') }.should.raise CLAide::Help
end
it "should create a new dir for the newly created pod" do
@sut.any_instance.stubs(:configure_template)
url = @sut::TEMPLATE_REPO
@sut.any_instance.expects(:git!).with("clone '#{url}' TestPod").once
run_command('lib', 'create', 'TestPod')
end
it "configures the template after cloning it passing the name of the Pod as the argument" do
@sut.any_instance.stubs(:clone_template)
dir = SpecHelper.temporary_directory + 'TestPod'
dir.mkpath
File.stubs(:exists?).with("configure").returns(true)
@sut.any_instance.expects(:system).with("./configure TestPod").once
run_command('lib', 'create', 'TestPod')
end
it "should show link to new pod guide after creation" do
@sut.any_instance.stubs(:clone_template)
@sut.any_instance.stubs(:configure_template)
output = run_command('lib', 'create', 'TestPod')
output.should.include? 'http://guides.cocoapods.org/making/making-a-cocoapod'
end
before do
@sut.any_instance.stubs(:configure_template)
end
it "should use the given template URL" do
template_url = 'https://github.com/custom/template.git'
@sut.any_instance.expects(:git!).with("clone '#{template_url}' TestPod").once
sut = run_command('lib', 'create', 'TestPod', template_url)
end
it "should use the default URL if no template URL is given" do
template_url = 'https://github.com/CocoaPods/pod-template.git'
@sut.any_instance.expects(:git!).with("clone '#{template_url}' TestPod").once
run_command('lib', 'create', 'TestPod')
end
end
describe Command::Lib::Lint do
it "lints the current working directory" do
Dir.chdir(fixture('integration/Reachability')) do
cmd = command('lib', 'lint', '--only-errors')
cmd = command('lib', 'lint', '--only-errors', '--quick')
cmd.run
UI.output.should.include "passed validation"
end
......@@ -35,14 +84,12 @@ module Pod
f << "spec.name = 'Broken'"
f << 'end'
}
tmp_validator = Validator.new('Broken.podspec')
lint_path = tmp_validator.validation_dir
lambda { run_command('lib', 'lint', 'Broken.podspec') }.should.raise Pod::Informative
Validator.any_instance.expects(:no_clean=).with(false)
Validator.any_instance.stubs(:perform_extensive_analysis)
should.raise Pod::Informative do
run_command('lib', 'lint', 'Broken.podspec')
end
UI.output.should.include "Missing required attribute"
lint_path.exist?.should == false
end
end
......@@ -53,29 +100,14 @@ module Pod
f << "spec.name = 'Broken'"
f << 'end'
}
lambda { run_command('lib', 'lint', 'Broken.podspec', '--no-clean') }.should.raise Pod::Informative
UI.output.should.include "Pods project available at"
UI.output.should.include "Missing required attribute"
lint_dir = UI.output[/.*Pods project available at `(.*)` for inspection./,1]
Pathname.new(lint_dir).exist?.should == true
end
end
end
describe Command::Lib do
it "should create a new dir for the newly created pod" do
run_command('lib', 'create', 'TestPod')
Dir.chdir(temporary_directory) do
Pathname.new(temporary_directory + 'TestPod').exist?.should == true
Validator.any_instance.expects(:no_clean=).with(true)
Validator.any_instance.stubs(:perform_extensive_analysis)
should.raise Pod::Informative do
run_command('lib', 'lint', 'Broken.podspec', '--no-clean')
end
UI.output.should.include "Missing required attribute"
UI.output.should.include "Pods project available at"
end
it "should show link to new pod guide after creation" do
output = run_command('lib', 'create', 'TestPod')
output.should.include? 'http://guides.cocoapods.org/making/making-a-cocoapod'
end
end
end
......@@ -28,6 +28,16 @@ module Pod
out.should.include('BananaLib')
out.should.not.include('JSONKit')
end
it "presents the known pods with versions" do
sets = SourcesManager.all_sets
jsonkit_set = sets.find { |s| s.name == 'JSONKit' }
out = run_command('list')
[ /BananaLib 1.0/,
/JSONKit #{jsonkit_set.versions.first}/,
/\d+ pods were found/
].each { |regex| out.should =~ regex }
end
end
end
......@@ -17,6 +17,32 @@ module Pod
exception.message.should.include "No `Podfile.lock' found in the current working directory"
end
end
it 'tells the user only about podspecs that have no parent' do
spec = Specification.new(nil, 'BlocksKit')
subspec = Specification.new(spec, 'UIKit')
set = mock
set.stubs(:versions).returns(['2.0'])
set.stubs(:specification).returns(spec)
subset = mock
subset.stubs(:specification).returns(subspec)
subset.stubs(:versions).returns(['2.0'])
version = mock
version.stubs(:version).returns('1.0')
Command::Outdated.any_instance.stubs(:spec_sets).returns([set, subset])
Command::Outdated.any_instance.stubs(:lockfile).returns(version)
run_command('outdated', '--no-repo-update')
UI.output.should.not.include('UIKit')
end
it 'tells the user about deprecated pods' do
spec = Specification.new(nil, 'AFNetworking')
spec.deprecated_in_favor_of = 'BlocksKit'
Command::Outdated.any_instance.stubs(:deprecated_pods).returns([spec])
Command::Outdated.any_instance.stubs(:updates).returns([])
run_command('outdated', '--no-repo-update')
UI.output.should.include('in favor of BlocksKit')
end
end
end
......@@ -34,13 +34,54 @@ module Pod
it "tells the user that no Lockfile was found in the current working dir" do
file = temporary_directory + 'Podfile'
File.open(file, 'w') {|f| f.write('platform :ios') }
File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "Reachability"')
end
Dir.chdir(temporary_directory) do
exception = lambda { run_command('update','--no-repo-update') }.should.raise Informative
exception = lambda { run_command('update', 'Reachability', '--no-repo-update') }.should.raise Informative
exception.message.should.include "No `Podfile.lock' found in the current working directory"
end
end
describe "tells the user that the Pods cannot be updated unless they are installed" do
extend SpecHelper::TemporaryRepos
before do
file = temporary_directory + 'Podfile'
File.open(file, 'w') do |f|
f.puts('platform :ios')
f.puts('pod "BananaLib", "1.0"')
end
podfile = Podfile.new do
platform :ios
pod 'BananaLib', '1.0'
end
specs = [
Specification.new do |s|
s.name = 'BananaLib'
s.version = '1.0'
end
]
Lockfile.generate(podfile, specs).write_to_disk(temporary_directory + 'Podfile.lock')
end
it "for a single missing Pod" do
Dir.chdir(temporary_directory) do
exception = lambda { run_command('update', 'Reachability', '--no-repo-update') }.should.raise Informative
exception.message.should.include "Pod `Reachability` is not installed and cannot be updated"
end
end
it "for multiple missing Pods" do
Dir.chdir(temporary_directory) do
exception = lambda { run_command('update', 'Reachability', 'BananaLib2', '--no-repo-update') }.should.raise Informative
exception.message.should.include "Pods `Reachability`, `BananaLib2` are not installed and cannot be updated"
end
end
end
end
#---------------------------------------------------------------------------#
......
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe Command::Push do
describe Command::Repo::Push do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
# Don't test push the spec to the trunk app
def command(*a)
super.tap { |cmd| cmd.stubs(:test_trunk) }
end
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
it "complains if it can't find the repo" do
Dir.chdir(fixture('banana-lib')) do
cmd = command('push', 'missing_repo')
cmd = command('repo', 'push', 'missing_repo')
cmd.expects(:check_if_master_repo)
cmd.expects(:validate_podspec_files).returns(true)
e = lambda { cmd.run }.should.raise Informative
e.message.should.match(/repo not found/)
......@@ -25,7 +21,7 @@ module Pod
it "complains if it can't find a spec" do
repo_make('test_repo')
e = lambda { run_command('push', 'test_repo') }.should.raise Pod::Informative
e = lambda { run_command('repo', 'push', 'test_repo') }.should.raise Pod::Informative
e.message.should.match(/Couldn't find any .podspec/)
end
......@@ -34,7 +30,7 @@ module Pod
Dir.chdir(temporary_directory) do
spec = "Spec.new do |s|; s.name = 'Broken'; s.version = '1.0' end"
File.open('Broken.podspec', 'w') {|f| f.write(spec) }
cmd = command('push', 'test_repo')
cmd = command('repo', 'push', 'test_repo')
Validator.any_instance.stubs(:validated?).returns(false)
e = lambda { cmd.run }.should.raise Pod::Informative
......@@ -69,11 +65,20 @@ module Pod
File.open(temporary_directory + 'BananaLib.podspec', 'w') {|f| f.write(spec_clean) }
end
it "refuses to push if the repo is not clean" do
Dir.chdir(test_repo_path) do
`git remote set-url origin https://github.com/CocoaPods/Specs.git`
end
cmd = command('repo', 'push', 'master')
e = lambda { cmd.run }.should.raise Pod::Informative
e.message.should.match(/use the `pod trunk push` command/)
end
it "refuses to push if the repo is not clean" do
Dir.chdir(test_repo_path) do
`touch DIRTY_FILE`
end
cmd = command('push', 'master')
cmd = command('repo', 'push', 'master')
cmd.expects(:validate_podspec_files).returns(true)
e = lambda { cmd.run }.should.raise Pod::Informative
e.message.should.match(/repo.*not clean/)
......@@ -81,8 +86,7 @@ module Pod
end
it "successfully pushes a spec" do
cmd = command('push', 'master')
cmd = command('repo', 'push', 'master')
Dir.chdir(@upstream) { `git checkout -b tmp_for_push -q` }
cmd.expects(:validate_podspec_files).returns(true)
Dir.chdir(temporary_directory) { cmd.run }
......
......@@ -2,7 +2,7 @@ require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe Command::Repo do
describe "In general" do
describe Command::Repo::Update do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
......@@ -23,10 +23,41 @@ module Pod
lambda { command('repo', 'update').run }.should.not.raise
end
it "updates a spec-repo" do
repo1 = repo_make('repo1')
repo2 = repo_clone('repo1', 'repo2')
repo_make_readme_change(repo1, 'Updated')
Dir.chdir(repo1) {`git commit -a -m "Update"`}
run_command('repo', 'update', 'repo2')
(repo2 + 'README').read.should.include 'Updated'
end
end
describe Command::Repo::Lint do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
require 'rest'
::REST.stubs(:head => stub(:success? => true))
end
it "lints a repository" do
repo = fixture('spec-repos/test_repo').to_s
lambda { run_command('repo', 'lint', repo) }.should.not.raise
end
end
describe Command::Repo::Add do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it "adds a spec-repo" do
run_command('repo', 'add', 'private', test_repo_path)
......@@ -46,13 +77,41 @@ module Pod
Dir.chdir(repo2.dir) { `git symbolic-ref HEAD` }.should.include? 'my-branch'
end
it "updates a spec-repo" do
repo1 = repo_make('repo1')
repo2 = repo_clone('repo1', 'repo2')
repo_make_readme_change(repo1, 'Updated')
Dir.chdir(repo1) {`git commit -a -m "Update"`}
run_command('repo', 'update', 'repo2')
(repo2 + 'README').read.should.include 'Updated'
it "adds a spec-repo by creating a shallow clone" do
Dir.chdir(test_repo_path) do
`echo 'touch' > touch && git add touch && git commit -m 'updated'`
end
# Need to use file:// to test local use of --depth=1
run_command('repo', 'add', 'private', '--shallow', "file://#{test_repo_path}")
Dir.chdir(config.repos_dir + 'private') do
`git log --pretty=oneline`.strip.split("\n").size.should == 1
end
end
end
describe Command::Repo::Remove do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it "complains when a repository name is missing" do
lambda { run_command('repo', 'remove') }.should.raise CLAide::Help
end
it "complains if the repository doesn't exist" do
lambda { run_command('repo', 'remove', 'nonexistant') }.should.raise CLAide::Help
end
it "complains if we do not have permission" do
File.stubs(:writable?).returns(false)
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
lambda { run_command('repo', 'remove', upstream) }.should.raise CLAide::Help
FileUtils.rm_rf(upstream)
end
it "removes a spec-repo" do
......
......@@ -50,10 +50,24 @@ module Pod
output.should.include? 'BananaLib'
end
it "shows a friendly message when locally searching with invalid regex" do
lambda { run_command('search', '+') }.should.raise CLAide::Help
end
describe "option --web" do
extend SpecHelper::TemporaryRepos
it "searches with invalid regex" do
Command::Search.any_instance.expects(:open!).with('http://cocoapods.org/?q=NSAttributedString%2BCCLFormat')
run_command('search', '--web', 'NSAttributedString+CCLFormat')
end
it "should url encode search queries" do
Command::Search.any_instance.expects(:open!).with('http://cocoapods.org/?q=NSAttributedString%2BCCLFormat')
run_command('search', '--web', 'NSAttributedString+CCLFormat')
end
it "searches the web via the open! command" do
Command::Search.any_instance.expects(:open!).with('http://cocoapods.org/?q=bananalib')
run_command('search', '--web', 'bananalib')
......
......@@ -39,6 +39,40 @@ module Pod
url.should == test_repo_path.to_s
end
it "creates a shallow clone of the `master` repo by default" do
Dir.chdir(test_repo_path) do
`echo 'touch' > touch && git add touch && git commit -m 'updated'`
end
# Need to use file:// to test local use of --depth=1
Command::Setup.any_instance.stubs(:read_only_url).returns("file://#{test_repo_path}")
run_command('setup')
Dir.chdir(config.repos_dir + 'master') do
`git log --pretty=oneline`.strip.split("\n").size.should == 1
end
end
it "creates a full clone of the `master` repo if requested" do
Dir.chdir(test_repo_path) do
`echo 'touch' > touch && git add touch && git commit -m 'updated'`
end
run_command('setup', '--no-shallow')
Dir.chdir(config.repos_dir + 'master') do
`git log --pretty=oneline`.strip.split("\n").size.should > 1
end
end
it "creates a full clone of the `master` repo when push access is requested" do
Dir.chdir(test_repo_path) do
`echo 'touch' > touch && git add touch && git commit -m 'updated'`
end
# Need to use file:// to test local use of --depth=1
Command::Setup.any_instance.stubs(:read_write_url).returns("file://#{test_repo_path}")
cmd = run_command('setup', '--push')
Dir.chdir(config.repos_dir + 'master') do
`git log --pretty=oneline`.strip.split("\n").size.should > 1
end
end
it "preserves push access for the `master` repo" do
output = run_command('setup')
output.should.not.include "push"
......
......@@ -136,7 +136,7 @@ module Pod
end
it "lints the current working directory" do
Dir.chdir(fixture('spec-repos') + 'master/JSONKit/1.4/') do
Dir.chdir(fixture('spec-repos') + 'master/Specs/JSONKit/1.4/') do
cmd = command('spec', 'lint', '--quick', '--only-errors')
cmd.run
UI.output.should.include "passed validation"
......@@ -145,7 +145,7 @@ module Pod
# @todo VCR is required in CocoaPods only for this test.
xit "lints a remote podspec" do
Dir.chdir(fixture('spec-repos') + 'master/JSONKit/1.4/') do
Dir.chdir(fixture('spec-repos') + 'master/Specs/JSONKit/1.4/') do
cmd = command('spec', 'lint', '--quick', '--only-errors', '--silent', 'https://github.com/CocoaPods/Specs/raw/master/A2DynamicDelegate/2.0.1/A2DynamicDelegate.podspec')
# VCR.use_cassette('linter', :record => :new_episodes) { }
lambda { cmd.run }.should.not.raise
......@@ -153,9 +153,9 @@ module Pod
end
before do
text = (fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec').read
text.gsub!(/.*license.*/, "s.license = { :file => 'some_file'}")
file = temporary_directory + 'JSONKit.podspec'
text = (fixture('spec-repos') + 'master/Specs/JSONKit/1.4/JSONKit.podspec.json').read
text.gsub!(/.*license.*/, '"license": { "file": "LICENSE" },')
file = temporary_directory + 'JSONKit.podspec.json'
File.open(file, 'w') {|f| f.write(text) }
@spec_path = file.to_s
end
......@@ -208,13 +208,13 @@ module Pod
it "cats the given podspec" do
lambda { command('spec', 'cat', 'AFNetworking').run }.should.not.raise
UI.output.should.include fixture('spec-repos/master/AFNetworking/1.2.0/AFNetworking.podspec').read
UI.output.should.include fixture('spec-repos/master/Specs/AFNetworking/2.3.1/AFNetworking.podspec.json').read
end
it "cats the first podspec from all podspecs" do
UI.next_input = "1\n"
run_command('spec', 'cat', '--show-all', 'AFNetworking')
UI.output.should.include fixture('spec-repos/master/AFNetworking/1.2.0/AFNetworking.podspec').read
UI.output.should.include fixture('spec-repos/master/Specs/AFNetworking/2.3.1/AFNetworking.podspec.json').read
end
end
......@@ -236,7 +236,7 @@ module Pod
ENV['EDITOR'] = 'podspeceditor'
lambda { command('spec', 'edit', 'AFNetworking').run }.should.raise SystemExit
UI.output.should.include '/bin/sh -i -c podspeceditor "$@" --'
UI.output.should.include 'fixtures/spec-repos/master/AFNetworking'
UI.output.should.include 'fixtures/spec-repos/master/Specs/AFNetworking'
end
it "will raise if no editor is found" do
......@@ -250,7 +250,7 @@ module Pod
UI.next_input = "1\n"
lambda { command('spec', 'edit', '--show-all', 'AFNetworking').run }.should.raise SystemExit
UI.output.should.include '/bin/sh -i -c podspeceditor "$@" --'
UI.output.should.include 'fixtures/spec-repos/master/AFNetworking/1.2.0/AFNetworking.podspec'
UI.output.should.include 'fixtures/spec-repos/master/Specs/AFNetworking/1.2.0/AFNetworking.podspec'
end
it "complains if it can't find a spec file for the given spec" do
......@@ -274,7 +274,7 @@ module Pod
it "returns the path of the specification with the given name" do
path = @sut.send(:get_path_of_spec, 'AFNetworking')
path.should == fixture('spec-repos') + 'master/AFNetworking/1.2.0/AFNetworking.podspec'
path.should == fixture('spec-repos') + 'master/Specs/AFNetworking/2.3.1/AFNetworking.podspec.json'
end
end
......
......@@ -5,14 +5,17 @@ module Pod
extend SpecHelper::Command
it "displays the current version number with the --version flag" do
lambda { Pod::Command.run(['--version']) }.should.raise SystemExit
UI.output.should.include VERSION
Pod::Command.version.should == VERSION
end
it "reports the location of the AFNetworking spec" do
lambda { Pod::Command.run(['spec', 'which', 'AFNetworking']) }.should.not.raise
UI.output.should.include 'spec/fixtures/spec-repos/master/AFNetworking'
UI.output.should.include 'spec/fixtures/spec-repos/master/Specs/AFNetworking'
end
it "doesn't let you run as root" do
Process.stubs(:uid).returns(0)
lambda { Pod::Command.run(['--version']) }.should.raise CLAide::Help
end
end
end
......@@ -17,8 +17,8 @@ module Pod
output.should.include? '1.1'
output.should.include? '[master repo]'
output.should.include? 'A fast & simple, yet powerful & flexible logging framework for Mac and iOS.'
output.should.include? 'https://github.com/robbiehanson/CocoaLumberjack'
output.should.include? 'https://github.com/robbiehanson/CocoaLumberjack.git'
output.should.include? 'https://github.com/CocoaLumberjack/CocoaLumberjack'
output.should.include? 'https://github.com/CocoaLumberjack/CocoaLumberjack.git'
end
it "presents the stats of a specification set" do
......@@ -36,11 +36,17 @@ module Pod
end
it "should print at least one subspec" do
@set = SourcesManager.search_by_name('RestKit').first
@set = SourcesManager.search(Dependency.new('RestKit'))
UI.pod(@set)
output = UI.output
output.should.include? "RestKit/Network"
end
it "presents only name and version of a specification set in :name_and_version mode" do
@set = SourcesManager.search_by_name('RestKit').first
UI.pod(@set, :name_and_version)
output = UI.output
output.should.include? "RestKit #{@set.versions.first}"
end
end
end
......@@ -186,8 +186,8 @@ end
# The file in the temporary directory after running the pod command.
#
def yaml_should_match(expected, produced)
expected_yaml = YAML::load(File.open(expected))
produced_yaml = YAML::load(File.open(produced))
expected_yaml = File.open(expected) { |f| YAML.load(f) }
produced_yaml = File.open(produced) { |f| YAML.load(f) }
# Remove CocoaPods version
expected_yaml.delete('COCOAPODS')
produced_yaml.delete('COCOAPODS')
......@@ -331,6 +331,10 @@ describe "Integration" do
check "install --no-repo-update", "install_subspecs"
end
describe "Installs a Pod with subspecs and does not duplicate the prefix header" do
check "install --no-repo-update", "install_subspecs_no_duplicate_prefix"
end
describe "Installs a Pod with a local source" do
check "install --no-repo-update", "install_local_source"
end
......@@ -356,13 +360,6 @@ describe "Integration" do
describe "Runs the Podfile callbacks" do
check "install --no-repo-update", "install_podfile_callbacks"
end
# @todo add tests for all the hooks API
#
describe "Runs the specification callbacks" do
check "install --no-repo-update", "install_spec_callbacks"
end
end
#--------------------------------------#
......@@ -370,7 +367,11 @@ describe "Integration" do
describe "Pod update" do
describe "Updates an existing installation" do
check "update --no-repo-update", "update"
check "update --no-repo-update", "update_all"
end
describe "Updates a selected Pod in an existing installation" do
check "update Reachability --no-repo-update", "update_selected"
end
end
......
......@@ -7,7 +7,6 @@ module Pod
Command.parse(%w{ install }).should.be.instance_of Command::Install
Command.parse(%w{ list }).should.be.instance_of Command::List
Command.parse(%w{ outdated }).should.be.instance_of Command::Outdated
Command.parse(%w{ push }).should.be.instance_of Command::Push
Command.parse(%w{ repo }).should.be.instance_of Command::Repo
Command.parse(%w{ repo add }).should.be.instance_of Command::Repo::Add
Command.parse(%w{ repo lint }).should.be.instance_of Command::Repo::Lint
......
require File.expand_path('../../spec_helper', __FILE__)
module Pod
describe Executable do
it 'shows the actual command on failure' do
e = lambda { Executable.execute_command('false',
'', true) }.should.raise Informative
e.message.should.match(/false/)
end
end
end
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe ExternalSources::AbstractExternalSource do
before do
dependency = Dependency.new("Reachability", :git => fixture('integration/Reachability'))
@subject = ExternalSources.from_dependency(dependency, nil)
end
#--------------------------------------#
describe "In general" do
it "compares to another" do
dependency_1 = Dependency.new("Reachability", :git => 'url')
dependency_2 = Dependency.new("Another_name", :git => 'url')
dependency_3 = Dependency.new("Reachability", :git => 'another_url')
dependency_1.should.be == dependency_1
dependency_1.should.not.be == dependency_2
dependency_1.should.not.be == dependency_3
end
it "fetches the specification from the remote stores it in the sandbox" do
config.sandbox.specification('Reachability').should == nil
@subject.fetch(config.sandbox)
config.sandbox.specification('Reachability').name.should == 'Reachability'
end
end
#--------------------------------------#
describe "Subclasses helpers" do
it "pre-downloads the Pod and stores the relevant information in the sandbox" do
sandbox = config.sandbox
@subject.send(:pre_download, sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
sandbox.predownloaded_pods.should == ["Reachability"]
sandbox.checkout_sources.should == {
"Reachability" => {
:git => fixture('integration/Reachability'),
:commit => "4ec575e4b074dcc87c44018cce656672a979b34a"
}
}
end
end
end
end
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe ExternalSources::DownloaderSource do
before do
params = {
:git => fixture('integration/Reachability'),
:branch => 'master'
}
dep = Dependency.new("Reachability", params)
@subject = ExternalSources.from_dependency(dep, nil)
end
it "creates a copy of the podspec" do
@subject.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "marks the Pod as pre-downloaded" do
@subject.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["Reachability"]
end
it "returns the description" do
expected = /from `.*Reachability`, branch `master`/
@subject.description.should.match(expected)
end
end
end
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe ExternalSources::PathSource do
before do
params = { :path => fixture('integration/Reachability') }
dependency = Dependency.new("Reachability", params)
podfile_path = fixture('integration/Podfile')
@subject = ExternalSources.from_dependency(dependency, podfile_path)
end
it "creates a copy of the podspec" do
@subject.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "supports the deprecated local key" do
params = { :local => fixture('integration/Reachability') }
dependency = Dependency.new("Reachability", params)
podfile_path = fixture('integration/Podfile')
@subject = ExternalSources.from_dependency(dependency, podfile_path)
@subject.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "returns the description" do
@subject.description.should.match %r|from `.*integration/Reachability`|
end
it "marks the Pod as local in the sandbox" do
@subject.fetch(config.sandbox)
config.sandbox.development_pods.should == {
"Reachability" => fixture('integration/Reachability').to_s
}
end
it "raises if the podspec cannot be found" do
@subject.stubs(:params).returns(:path => temporary_directory)
should.raise Informative do
@subject.fetch(config.sandbox)
end.message.should.match /No podspec found for `Reachability` in `#{temporary_directory}`/
it "marks a pod as relative" do
@subject.stubs(:params).returns(:path => './Reachability')
Pathname.any_instance.stubs(:exist?).returns(true)
config.sandbox.stubs(:store_podspec)
@subject.fetch(config.sandbox)
config.sandbox.local_path_was_absolute?('Reachability').should.be.false
end
it "marks a pod as absolute" do
@subject.stubs(:params).returns(:path => '/path/Reachability')
Pathname.any_instance.stubs(:exist?).returns(true)
config.sandbox.stubs(:store_podspec)
@subject.fetch(config.sandbox)
config.sandbox.local_path_was_absolute?('Reachability').should.be.true
end
end
describe "#podspec_path" do
it "handles absolute paths" do
@subject.stubs(:params).returns(:path => fixture('integration/Reachability'))
path = @subject.send(:podspec_path)
path.should == fixture('integration/Reachability/Reachability.podspec')
end
it "handles paths when there is no podfile path" do
@subject.stubs(:podfile_path).returns(nil)
@subject.stubs(:params).returns(:path => fixture('integration/Reachability'))
path = @subject.send(:podspec_path)
path.should == fixture('integration/Reachability/Reachability.podspec')
end
it "handles relative paths" do
@subject.stubs(:params).returns(:path => 'Reachability')
path = @subject.send(:podspec_path)
path.should == fixture('integration/Reachability/Reachability.podspec')
end
it "expands the tilde" do
File.stubs(:exist?).returns(true)
@subject.stubs(:params).returns(:path => '~/Reachability')
Pathname.any_instance.stubs(:exist?).returns(true)
path = @subject.send(:podspec_path)
path.should == Pathname(ENV['HOME']) + 'Reachability/Reachability.podspec'
end
end
describe '#absolute?' do
it 'returns that a path is relative' do
result = @subject.send(:absolute?, './ThirdPartyCode/UrbanAirship')
result.should.be.false
end
it "consider relative paths not explicitly set from the current dir" do
result = @subject.send(:absolute?, './ThirdPartyCode/UrbanAirship')
result.should.be.false
end
it 'returns that a path is absolute' do
result = @subject.send(:absolute?, '/path/to/UrbanAirship')
result.should.be.true
end
it 'considers absolute paths specified with the tilde' do
result = @subject.send(:absolute?, '~/path/to/UrbanAirship')
result.should.be.true
end
end
end
end
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe ExternalSources::PodspecSource do
before do
podspec_path = fixture('integration/Reachability/Reachability.podspec')
dependency = Dependency.new("Reachability", :podspec => podspec_path.to_s)
podfile_path = fixture('integration/Podfile')
@subject = ExternalSources.from_dependency(dependency, podfile_path)
end
it "creates a copy of the podspec" do
@subject.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "returns the description" do
@subject.description.should.match %r|from `.*Reachability/Reachability.podspec`|
end
describe "Helpers" do
it "handles absolute paths" do
@subject.stubs(:params).returns(:podspec => fixture('integration/Reachability'))
path = @subject.send(:podspec_uri)
path.should == fixture('integration/Reachability/Reachability.podspec').to_s
end
it "handles paths when there is no podfile path" do
@subject.stubs(:podfile_path).returns(nil)
@subject.stubs(:params).returns(:podspec => fixture('integration/Reachability'))
path = @subject.send(:podspec_uri)
path.should == fixture('integration/Reachability/Reachability.podspec').to_s
end
it "handles relative paths" do
@subject.stubs(:params).returns(:podspec => 'Reachability')
path = @subject.send(:podspec_uri)
path.should == fixture('integration/Reachability/Reachability.podspec').to_s
end
it "expands the tilde" do
File.stubs(:exist?).returns(true)
@subject.stubs(:params).returns(:podspec => '~/Reachability')
path = @subject.send(:podspec_uri)
path.should == ENV['HOME'] + '/Reachability/Reachability.podspec'
end
it "handles URLs" do
@subject.stubs(:params).returns(:podspec => "http://www.example.com/Reachability.podspec")
path = @subject.send(:podspec_uri)
path.should == "http://www.example.com/Reachability.podspec"
end
end
end
end
require File.expand_path('../../spec_helper', __FILE__)
module Pod
describe ExternalSources do
it "returns the instance of appropriate concrete class according to the parameters" do
git = Dependency.new("Reachability", :git => nil)
svn = Dependency.new("Reachability", :svn => nil)
podspec = Dependency.new("Reachability", :podspec => nil)
local = Dependency.new("Reachability", :local => nil)
path = Dependency.new("Reachability", :path => nil)
ExternalSources.from_dependency(git, nil).class.should == ExternalSources::GitSource
ExternalSources.from_dependency(svn, nil).class.should == ExternalSources::SvnSource
ExternalSources.from_dependency(podspec, nil).class.should == ExternalSources::PodspecSource
ExternalSources.from_dependency(local, nil).class.should == ExternalSources::PathSource
ExternalSources.from_dependency(path, nil).class.should == ExternalSources::PathSource
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::AbstractExternalSource do
before do
dependency = Dependency.new("Reachability", :git => fixture('integration/Reachability'))
@external_source = ExternalSources.from_dependency(dependency, nil)
end
#--------------------------------------#
describe "In general" do
it "compares to another" do
dependency_1 = Dependency.new("Reachability", :git => 'url')
dependency_2 = Dependency.new("Another_name", :git => 'url')
dependency_3 = Dependency.new("Reachability", :git => 'another_url')
dependency_1.should.be == dependency_1
dependency_1.should.not.be == dependency_2
dependency_1.should.not.be == dependency_3
end
it "fetches the specification from the remote stores it in the sandbox" do
config.sandbox.specification('Reachability').should == nil
@external_source.fetch(config.sandbox)
config.sandbox.specification('Reachability').name.should == 'Reachability'
end
end
#--------------------------------------#
describe "Subclasses helpers" do
it "pre-downloads the Pod and stores the relevant information in the sandbox" do
sandbox = config.sandbox
@external_source.send(:pre_download, sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
sandbox.predownloaded_pods.should == ["Reachability"]
sandbox.checkout_sources.should == {
"Reachability" => {
:git => fixture('integration/Reachability'),
:commit => "4ec575e4b074dcc87c44018cce656672a979b34a"
}
}
end
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::GitSource do
before do
dependency = Dependency.new("Reachability", :git => fixture('integration/Reachability'))
@external_source = ExternalSources.from_dependency(dependency, nil)
end
it "creates a copy of the podspec" do
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "marks a LocalPod as downloaded" do
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["Reachability"]
end
it "returns the description" do
@external_source.description.should.match %r|from `.*Reachability`|
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::SvnSource do
before do
dependency = Dependency.new("SvnSource", :svn => "file://#{fixture('subversion-repo/trunk')}")
@external_source = ExternalSources.from_dependency(dependency, nil)
end
it "creates a copy of the podspec" do
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/SvnSource.podspec'
path.should.exist?
end
it "marks a LocalPod as downloaded" do
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["SvnSource"]
@subject = ExternalSources
end
it "returns the description" do
@external_source.description.should.match %r|from `.*subversion-repo/trunk`|
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::MercurialSource do
before do
dependency = Dependency.new("MercurialSource", :hg => fixture('mercurial-repo'))
@external_source = ExternalSources.from_dependency(dependency, nil)
describe "from_dependency" do
it "supports a podspec source" do
dep = Dependency.new("Reachability", :podspec => nil)
klass = @subject.from_dependency(dep, nil).class
klass.should == @subject::PodspecSource
end
it "creates a copy of the podspec" do
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/MercurialSource.podspec'
path.should.exist?
it "supports a path source" do
dep = Dependency.new("Reachability", :path => nil)
klass = @subject.from_dependency(dep, nil).class
klass.should == @subject::PathSource
end
it "marks a LocalPod as downloaded" do
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["MercurialSource"]
it "supports a path source specified with the legacy :local key" do
dep = Dependency.new("Reachability", :local => nil)
klass = @subject.from_dependency(dep, nil).class
klass.should == @subject::PathSource
end
it "returns the description" do
@external_source.description.should.match %r|from `.*/mercurial-repo`|
it "supports all the strategies implemented by the downloader" do
[:git, :svn, :hg, :bzr, :http].each do |strategy|
dep = Dependency.new("Reachability", strategy => nil)
klass = @subject.from_dependency(dep, nil).class
klass.should == @subject::DownloaderSource
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::BazaarSource do
before do
dependency = Dependency.new("BazaarSource", :bzr => fixture('bzr-repo'))
@external_source = ExternalSources.from_dependency(dependency, nil)
end
it "creates a copy of the podspec" do
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/BazaarSource.podspec'
path.should.exist?
end
it "marks a LocalPod as downloaded" do
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["BazaarSource"]
end
it "returns the description" do
@external_source.description.should.match %r|from `.*/bzr-repo`|
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::PodspecSource do
before do
podspec_path = fixture('integration/Reachability/Reachability.podspec')
dependency = Dependency.new("Reachability", :podspec => podspec_path.to_s)
podfile_path = fixture('integration/Podfile')
@external_source = ExternalSources.from_dependency(dependency, podfile_path)
end
it "creates a copy of the podspec" do
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "returns the description" do
@external_source.description.should.match %r|from `.*Reachability/Reachability.podspec`|
end
describe "Helpers" do
it "handles absolute paths" do
@external_source.stubs(:params).returns(:podspec => fixture('integration/Reachability'))
path = @external_source.send(:podspec_uri)
path.should == fixture('integration/Reachability/Reachability.podspec').to_s
end
it "handles paths when there is no podfile path" do
@external_source.stubs(:podfile_path).returns(nil)
@external_source.stubs(:params).returns(:podspec => fixture('integration/Reachability'))
path = @external_source.send(:podspec_uri)
path.should == fixture('integration/Reachability/Reachability.podspec').to_s
end
it "handles relative paths" do
@external_source.stubs(:params).returns(:podspec => 'Reachability')
path = @external_source.send(:podspec_uri)
path.should == fixture('integration/Reachability/Reachability.podspec').to_s
end
it "expands the tilde" do
@external_source.stubs(:params).returns(:podspec => '~/Reachability')
path = @external_source.send(:podspec_uri)
path.should == ENV['HOME'] + '/Reachability/Reachability.podspec'
end
it "handles urls" do
@external_source.stubs(:params).returns(:podspec => "http://www.example.com/Reachability.podspec")
path = @external_source.send(:podspec_uri)
path.should == "http://www.example.com/Reachability.podspec"
end
end
end
#---------------------------------------------------------------------------#
describe ExternalSources::PathSource do
before do
podspec_path = fixture('integration/Reachability/Reachability.podspec')
dependency = Dependency.new("Reachability", :path => fixture('integration/Reachability'))
podfile_path = fixture('integration/Podfile')
@external_source = ExternalSources.from_dependency(dependency, podfile_path)
end
it "creates a copy of the podspec" do
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "creates a copy of the podspec [Deprecated local option]" do
dependency = Dependency.new("Reachability", :local => fixture('integration/Reachability'))
podfile_path = fixture('integration/Podfile')
external_source = ExternalSources.from_dependency(dependency, podfile_path)
external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "returns the description" do
@external_source.description.should.match %r|from `.*integration/Reachability`|
end
it "marks the Pod as local in the sandbox" do
@external_source.fetch(config.sandbox)
config.sandbox.development_pods.should == {
"Reachability" => fixture('integration/Reachability').to_s
}
end
describe "Helpers" do
it "handles absolute paths" do
@external_source.stubs(:params).returns(:path => fixture('integration/Reachability'))
path = @external_source.send(:podspec_path)
path.should == fixture('integration/Reachability/Reachability.podspec')
end
it "handles paths when there is no podfile path" do
@external_source.stubs(:podfile_path).returns(nil)
@external_source.stubs(:params).returns(:path => fixture('integration/Reachability'))
path = @external_source.send(:podspec_path)
path.should == fixture('integration/Reachability/Reachability.podspec')
end
it "handles relative paths" do
@external_source.stubs(:params).returns(:path => 'Reachability')
path = @external_source.send(:podspec_path)
path.should == fixture('integration/Reachability/Reachability.podspec')
end
it "expands the tilde" do
@external_source.stubs(:params).returns(:path => '~/Reachability')
Pathname.any_instance.stubs(:exist?).returns(true)
path = @external_source.send(:podspec_path)
path.should == Pathname(ENV['HOME']) + 'Reachability/Reachability.podspec'
end
it "raises if the podspec cannot be found" do
@external_source.stubs(:params).returns(:path => temporary_directory)
e = lambda { @external_source.send(:podspec_path) }.should.raise Informative
e.message.should.match /No podspec found/
end
end
end
#---------------------------------------------------------------------------#
end
......@@ -21,6 +21,43 @@ module Pod
EOS
end
# @note Declaring a subspec was found in issue #1449 to generate duplicates of the prefix_header_contents
it "does not duplicate the contents of the specification's prefix header when a subspec is declared" do
@spec.prefix_header_contents = '#import "BlocksKit.h"'
@spec.prefix_header_file = nil
@spec.subspec 'UI' do |subspec|
subspec.source_files = 'Source/UI/*.{h,m}'
end
@gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif
#import "BlocksKit.h"
EOS
end
# @note Declaring a subspec was found in issue #1449 to generate duplicates of the prefix_header_contents
it "does not duplicate the contents of the specification's prefix header when a subspec is declared multiple times" do
@spec.prefix_header_contents = '#import "BlocksKit.h"'
@spec.prefix_header_file = nil
@spec.subspec 'UI' do |su|
su.source_files = 'Source/UI/*.{h,m}'
end
@spec.subspec 'Helpers' do |sh|
sh.source_files = 'Source/Helpers/*.{h,m}'
end
@gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#endif
#import "BlocksKit.h"
EOS
end
it "includes the contents of the specification's prefix header file" do
@gen.generate.should == <<-EOS.strip_heredoc
#ifdef __OBJC__
......
......@@ -95,14 +95,14 @@ module Pod
it "considers changed a Pod whose specification is in head mode if in update mode" do
@sandbox.stubs(:head_pod?).returns(true)
@analyzer.stubs(:update_mode).returns(true)
@analyzer.stubs(:update_mode?).returns(true)
@analyzer.send(:pod_changed?, 'BananaLib').should == true
end
it "doesn't consider changed a Pod whose specification is in head mode if not in update mode" do
@sandbox.stubs(:head_pod?).returns(true)
@analyzer.stubs(:sandbox_head_version?).returns(true)
@analyzer.stubs(:update_mode).returns(false)
@analyzer.stubs(:update_mode?).returns(false)
@analyzer.send(:pod_changed?, 'BananaLib').should == false
end
......
......@@ -128,7 +128,7 @@ module Pod
end
it "does not lock the dependencies in update mode" do
@analyzer.update_mode = true
@analyzer.update = true
@analyzer.analyze
@analyzer.send(:locked_dependencies).map(&:to_s).should == []
end
......@@ -140,19 +140,19 @@ module Pod
podfile_state.added << "BananaLib"
@analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state))
@podfile.stubs(:dependencies).returns([Dependency.new('BananaLib', :git => "example.com")])
ExternalSources::GitSource.any_instance.expects(:fetch)
ExternalSources::DownloaderSource.any_instance.expects(:fetch)
@analyzer.send(:fetch_external_sources)
end
xit "it fetches the specification from either the sandbox or from the remote be default" do
dependency = Dependency.new('Name', :git => 'www.example.com')
ExternalSources::GitSource.any_instance.expects(:specification_from_external).returns(Specification.new).once
ExternalSources::DownloaderSource.any_instance.expects(:specification_from_external).returns(Specification.new).once
@resolver.send(:set_from_external_source, dependency)
end
xit "it fetches the specification from the remote if in update mode" do
dependency = Dependency.new('Name', :git => 'www.example.com')
ExternalSources::GitSource.any_instance.expects(:specification).returns(Specification.new).once
ExternalSources::DownloaderSource.any_instance.expects(:specification).returns(Specification.new).once
@resolver.update_external_specs = false
@resolver.send(:set_from_external_source, dependency)
end
......
......@@ -61,6 +61,36 @@ module Pod
}
end
it "cleans up directory when an error occurs during download" do
config.sandbox.store_head_pod('BananaLib')
pod_folder = config.sandbox.root + 'BananaLib'
partially_downloaded_file = pod_folder + 'partially_downloaded_file'
mock_downloader = Object.new
singleton_class = class << mock_downloader; self; end
singleton_class.send(:define_method, :download_head) do
FileUtils.mkdir_p(pod_folder)
FileUtils.touch(partially_downloaded_file)
raise("some network error")
end
@installer.stubs(:downloader).returns(mock_downloader)
lambda {
@installer.install!
}.should.raise(RuntimeError).message.should.equal('some network error')
partially_downloaded_file.should.not.exist
end
it "fails when using :head for Http source" do
config.sandbox.store_head_pod('BananaLib')
@spec.source = { :http => 'http://dl.google.com/googleadmobadssdk/googleadmobsearchadssdkios.zip' }
@spec.source_files = 'GoogleAdMobSearchAdsSDK/*.h'
Pod::Downloader::Http.any_instance.stubs(:download_head)
should.raise Informative do
@installer.install!
end.message.should.match /does not support the :head option, as it uses a Http source./
end
end
#--------------------------------------#
......@@ -83,6 +113,13 @@ module Pod
@installer.install!
end.message.should.match /command not found/
end
it "unsets $CDPATH environment variable" do
ENV['CDPATH'] = "BogusPath"
@spec.prepare_command = "cd Classes;ls Banana.h"
lambda { @installer.install! }.should.not.raise
end
end
#--------------------------------------#
......
......@@ -34,7 +34,10 @@ module Pod
@integrator.integrate!
workspace_path = @integrator.send(:workspace_path)
workspace = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
workspace.projpaths.find { |path| path =~ /Pods.xcodeproj/ }.should.not.be.nil
pods_project_ref = workspace.file_references.find do |ref|
ref.path =~ /Pods.xcodeproj/
end
pods_project_ref.should.not.be.nil
end
it "integrates the user targets" do
......@@ -60,7 +63,7 @@ module Pod
@integrator.send(:create_workspace)
workspace_path = @integrator.send(:workspace_path)
saved = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
saved.projpaths.should == [
saved.file_references.map(&:path).should == [
"SampleProject/SampleProject.xcodeproj",
"Pods/Pods.xcodeproj"
]
......@@ -68,22 +71,24 @@ module Pod
it "updates an existing workspace if needed" do
workspace_path = @integrator.send(:workspace_path)
workspace = Xcodeproj::Workspace.new('SampleProject/SampleProject.xcodeproj')
ref = Xcodeproj::Workspace::FileReference.new('SampleProject/SampleProject.xcodeproj', 'group')
workspace = Xcodeproj::Workspace.new(ref)
workspace.save_as(workspace_path)
@integrator.send(:create_workspace)
saved = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
saved.projpaths.should == [
saved.file_references.map(&:path).should == [
"SampleProject/SampleProject.xcodeproj",
"Pods/Pods.xcodeproj"
]
end
it "doesn't write the workspace if not needed" do
projpaths = [
"SampleProject/SampleProject.xcodeproj",
"Pods/Pods.xcodeproj"
file_references = [
Xcodeproj::Workspace::FileReference.new('SampleProject/SampleProject.xcodeproj', 'group'),
Xcodeproj::Workspace::FileReference.new('Pods/Pods.xcodeproj', 'group')
]
workspace = Xcodeproj::Workspace.new(projpaths)
workspace = Xcodeproj::Workspace.new(file_references)
workspace_path = @integrator.send(:workspace_path)
workspace.save_as(workspace_path)
Xcodeproj::Workspace.expects(:save_as).never
......@@ -91,12 +96,13 @@ module Pod
end
it "only appends projects to the workspace and never deletes one" do
workspace = Xcodeproj::Workspace.new('user_added_project.xcodeproj')
ref = Xcodeproj::Workspace::FileReference.new('user_added_project.xcodeproj', 'group')
workspace = Xcodeproj::Workspace.new(ref)
workspace_path = @integrator.send(:workspace_path)
workspace.save_as(workspace_path)
@integrator.send(:create_workspace)
saved = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
saved.projpaths.should == [
saved.file_references.map(&:path).should == [
'user_added_project.xcodeproj',
"SampleProject/SampleProject.xcodeproj",
"Pods/Pods.xcodeproj"
......@@ -104,16 +110,17 @@ module Pod
end
it "preserves the order of the projects in the workspace" do
projpaths = [
"Pods/Pods.xcodeproj",
"SampleProject/SampleProject.xcodeproj",
file_references = [
Xcodeproj::Workspace::FileReference.new('Pods/Pods.xcodeproj', 'group'),
Xcodeproj::Workspace::FileReference.new('SampleProject/SampleProject.xcodeproj', 'group'),
]
workspace = Xcodeproj::Workspace.new(projpaths)
workspace = Xcodeproj::Workspace.new(file_references)
workspace_path = @integrator.send(:workspace_path)
workspace.save_as(workspace_path)
@integrator.send(:create_workspace)
saved = Xcodeproj::Workspace.new_from_xcworkspace(workspace_path)
saved.projpaths.should == [
saved.file_references.map(&:path).should == [
"Pods/Pods.xcodeproj",
"SampleProject/SampleProject.xcodeproj",
]
......
......@@ -21,6 +21,16 @@ def generate_podfile(pods = ['JSONKit'])
end
end
# @return [Podfile]
#
def generate_local_podfile
podfile = Pod::Podfile.new do
platform :ios
xcodeproj SpecHelper.fixture('SampleProject/SampleProject'), 'Test' => :debug, 'App Store' => :release
pod 'Reachability', :path => SpecHelper.fixture('integration/Reachability')
end
end
#-----------------------------------------------------------------------------#
module Pod
......@@ -42,6 +52,7 @@ module Pod
@installer.stubs(:download_dependencies)
@installer.stubs(:generate_pods_project)
@installer.stubs(:integrate_user_project)
@installer.stubs(:perform_post_install_actions)
end
it "in runs the pre-install hooks before cleaning the Pod sources" do
......@@ -87,6 +98,19 @@ module Pod
@installer.install!
end
it 'prints a list of deprecated pods' do
spec = Spec.new
spec.name = 'RestKit'
spec.deprecated_in_favor_of = 'AFNetworking'
spec_two = Spec.new
spec_two.name = 'BlocksKit'
spec_two.deprecated = true
@installer.stubs(:root_specs).returns([spec, spec_two])
@installer.send(:warn_for_deprecations)
UI.warnings.should.include 'deprecated in favor of AFNetworking'
UI.warnings.should.include 'BlocksKit has been deprecated'
end
end
#-------------------------------------------------------------------------#
......@@ -113,8 +137,8 @@ module Pod
end
it "configures the analyzer to use update mode if appropriate" do
@installer.update_mode = true
Installer::Analyzer.any_instance.expects(:update_mode=).with(true)
@installer.update = true
Installer::Analyzer.any_instance.expects(:update=).with(true)
@installer.send(:analyze)
@installer.aggregate_targets.map(&:name).sort.should == ['Pods']
@installer.pod_targets.map(&:name).sort.should == ['Pods-JSONKit']
......@@ -216,6 +240,22 @@ module Pod
@installer.installed_specs.should == [spec]
end
it "prints the previous version of a pod while updating the spec" do
spec = Spec.new
spec.name = 'RestKit'
spec.version = '2.0'
manifest = Lockfile.new({})
manifest.stubs(:version).with('RestKit').returns('1.0')
@installer.sandbox.stubs(:manifest).returns(manifest)
@installer.stubs(:root_specs).returns([spec])
sandbox_state = Installer::Analyzer::SpecsState.new
sandbox_state.changed << 'RestKit'
@installer.stubs(:sandbox_state).returns(sandbox_state)
@installer.expects(:install_source_of_pod).with('RestKit')
@installer.send(:install_pod_sources)
UI.output.should.include 'was 1.0'
end
#--------------------------------------#
describe "#clean" do
......@@ -269,6 +309,15 @@ module Pod
@installer.pods_project.class.should == Pod::Project
end
it "preserves Pod paths specified as absolute or rooted to home" do
local_podfile = generate_local_podfile
local_installer = Installer.new(config.sandbox, local_podfile)
local_installer.send(:analyze)
local_installer.send(:prepare_pods_project)
group = local_installer.pods_project.group_for_spec('Reachability')
Pathname.new(group.path).should.be.absolute
end
it "adds the Podfile to the Pods project" do
config.stubs(:podfile_path).returns(Pathname.new('/Podfile'))
@installer.send(:prepare_pods_project)
......@@ -367,11 +416,13 @@ module Pod
end
it "recursively sorts the project" do
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
@installer.pods_project.main_group.expects(:sort)
@installer.send(:write_pod_project)
end
it "saves the project to the given path" do
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
path = temporary_directory + 'Pods/Pods.xcodeproj'
@installer.pods_project.expects(:save)
@installer.send(:write_pod_project)
......@@ -440,9 +491,6 @@ module Pod
library_rep = stub()
@installer.expects(:installer_rep).returns(installer_rep)
@installer.expects(:pod_rep).with('JSONKit').returns(pod_rep)
@installer.expects(:library_rep).with(@aggregate_target).returns(library_rep)
@spec.expects(:pre_install!)
@installer.podfile.expects(:pre_install!).with(installer_rep)
@installer.send(:run_pre_install_hooks)
end
......@@ -452,8 +500,6 @@ module Pod
target_installer_data = stub()
@installer.expects(:installer_rep).returns(installer_rep)
@installer.expects(:library_rep).with(@aggregate_target).returns(target_installer_data)
@spec.expects(:post_install!)
@installer.podfile.expects(:post_install!).with(installer_rep)
@installer.send(:run_post_install_hooks)
end
......@@ -469,11 +515,7 @@ module Pod
@installer.stubs(:pod_targets).returns([pod_target_ios, pod_target_osx])
@installer.stubs(:installer_rep).returns(stub())
@installer.stubs(:library_rep).with(@aggregate_target).returns(target_installer_data).twice
@installer.podfile.expects(:pre_install!)
@spec.expects(:post_install!).with(target_installer_data).once
@installer.send(:run_pre_install_hooks)
@installer.send(:run_post_install_hooks)
end
......@@ -510,9 +552,7 @@ module Pod
libs = @installer.send(:libraries_using_spec, @spec)
libs.map(&:name).should == ['Pods']
end
end
end
end
......@@ -32,7 +32,7 @@ module Pod
specs.map(&:to_s).should == [
"A2DynamicDelegate (2.0.2)",
"BlocksKit (1.5.2)",
"libffi (3.0.11)"
"libffi (3.0.13)"
]
end
......@@ -43,7 +43,7 @@ module Pod
specs.map(&:to_s).should == [
"A2DynamicDelegate (2.0.2)",
"BlocksKit (1.5.2)",
"libffi (3.0.11)"
"libffi (3.0.13)"
]
end
......@@ -107,7 +107,7 @@ module Pod
it "includes all the subspecs of a specification node" do
@podfile = Podfile.new do
platform :ios
platform :ios, '7.0'
pod 'RestKit', '0.10.3'
end
resolver = Resolver.new(config.sandbox, @podfile)
......@@ -121,11 +121,14 @@ module Pod
RestKit
RestKit/JSON
RestKit/Network
RestKit/ObjectMapping
RestKit/ObjectMapping/Core
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/ObjectMapping/XML
RestKit/UI
SOCKit
XMLReader
cocoa-oauth
}
end
......
......@@ -107,6 +107,18 @@ module Pod
@sandbox.specification('BananaLib').name.should == 'BananaLib'
end
it "loads the stored specification from the original path" do
spec_file = fixture('banana-lib/BananaLib.podspec')
spec = Specification.from_file(spec_file)
Specification.expects(:from_file).with do
Dir.pwd == fixture('banana-lib').to_s
end.twice.returns(spec)
@sandbox.store_podspec('BananaLib', spec_file)
@sandbox.store_local_path('BananaLib', fixture('banana-lib'))
@sandbox.specification('BananaLib')
end
it "returns the directory where to store the specifications" do
@sandbox.specifications_dir.should == temporary_directory + 'Sandbox/Local Podspecs'
end
......
require File.expand_path('../../spec_helper', __FILE__)
def set_up_test_repo_for_update
set_up_test_repo
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
Dir.chdir(test_repo_path) do
`git remote add origin #{upstream}`
`git remote -v`
`git fetch -q`
`git branch --set-upstream-to=origin/master master`
`git config branch.master.rebase true`
end
config.repos_dir = SpecHelper.tmp_repos_path
end
def merge_conflict_version_yaml
text = <<-VERSION.strip_heredoc
---
<<<<<<< HEAD
min: 0.18.1
=======
min: 0.29.0
>>>>>>> 8365d0ad18508175bbde31b9dd2bdaf1be49214f
last: 0.29.0
VERSION
end
module Pod
describe SourcesManager do
......@@ -87,19 +113,17 @@ module Pod
extend SpecHelper::TemporaryRepos
it "update source backed by a git repository" do
set_up_test_repo
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
Dir.chdir(test_repo_path) do
`git remote add origin #{upstream}`
`git remote -v`
`git fetch -q`
`git branch --set-upstream-to=origin/master master`
set_up_test_repo_for_update
SourcesManager.update(test_repo_path.basename.to_s, true)
UI.output.should.match /is up to date/
end
config.repos_dir = SpecHelper.tmp_repos_path
it "uses the only fast forward git option" do
set_up_test_repo_for_update
SourcesManager.expects(:git!).with() { |options| options.should.match /--ff-only/ }
SourcesManager.update(test_repo_path.basename.to_s, true)
UI.output.should.match /Already up-to-date/
end
it 'returns whether a source has a reachable git remote' do
......@@ -122,9 +146,23 @@ module Pod
SourcesManager.stubs(:version_information).returns({ 'min' => '999.0' })
e = lambda { SourcesManager.check_version_information(temporary_directory) }.should.raise Informative
e.message.should.match /Update CocoaPods/
e.message.should.match /(currently using #{Pod::VERSION})/
SourcesManager.stubs(:version_information).returns({ 'max' => '0.0.1' })
e = lambda { SourcesManager.check_version_information(temporary_directory) }.should.raise Informative
e.message.should.match /Update CocoaPods/
e.message.should.match /(currently using #{Pod::VERSION})/
end
it 'raises when reading version information with merge conflict' do
Pathname.any_instance.stubs(:read).returns(merge_conflict_version_yaml)
e = lambda { SourcesManager.version_information(SourcesManager.master_repo_dir) }.should.raise Informative
e.message.should.match /Repairing-Our-Broken-Specs-Repository/
end
it 'returns whether a path is writable' do
path = '/Users/'
Pathname.any_instance.stubs(:writable?).returns(true)
SourcesManager.send(:path_writable?, path).should.be.true
end
it "returns whether a repository is compatible" do
......
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe UserInterface::ErrorReport do
def remove_color(string)
string.gsub(/\e\[(\d+)m/, '')
end
describe 'In general' do
before do
@exception = Informative.exception('at - (~/code.rb):')
@exception.stubs(:backtrace).returns(['Line 1', 'Line 2'])
@report = UserInterface::ErrorReport
end
it 'returns a well-structured report' do
expected = <<-EOS
――― MARKDOWN TEMPLATE ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
### Report
* What did you do?
* What did you expect to happen?
* What happened instead?
### Stack
```
CocoaPods : #{Pod::VERSION}
Ruby : #{RUBY_DESCRIPTION}
RubyGems : #{Gem::VERSION}
Host : :host_information
Xcode : :xcode_information
Ruby lib dir : #{RbConfig::CONFIG['libdir']}
Repositories : repo_1
repo_2
```
### Podfile
```ruby
```
### Error
```
Pod::Informative - [!] at - (~/code.rb):
Line 1
Line 2
```
――― TEMPLATE END ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
[!] Oh no, an error occurred.
Search for existing github issues similar to yours:
https://github.com/CocoaPods/CocoaPods/search?q=%5B%21%5D+at+-&type=Issues
If none exists, create a ticket, with the template displayed above, on:
https://github.com/CocoaPods/CocoaPods/issues/new
Don't forget to anonymize any private data!
EOS
@report.stubs(:markdown_podfile).returns <<-EOS
### Podfile
```ruby
```
EOS
@report.stubs(:host_information).returns(':host_information')
@report.stubs(:xcode_information).returns(':xcode_information')
@report.stubs(:repo_information).returns(['repo_1', 'repo_2'])
report = remove_color(@report.report(@exception))
report.should == expected
end
it 'strips the local path from the exception message' do
message = @report.send(:pathless_exception_message, @exception.message)
message = remove_color(message)
message.should == '[!] at -'
end
end
end
end
require File.expand_path('../../spec_helper', __FILE__)
require 'webmock'
module Bacon
class Context
alias_method :after_webmock, :after
def after(&block)
after_webmock do
block.call()
WebMock.reset!
end
end
end
end
module Pod
describe Validator do
......@@ -9,7 +22,7 @@ module Pod
# @return [void]
#
def write_podspec(text, name = 'JSONKit.podspec')
def write_podspec(text, name = 'JSONKit.podspec.json')
file = temporary_directory + name
File.open(file, 'w') {|f| f.write(text) }
file
......@@ -18,7 +31,7 @@ module Pod
# @return [String]
#
def stub_podspec(pattern = nil, replacement = nil)
spec = (fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec').read
spec = (fixture('spec-repos') + 'master/Specs/JSONKit/1.4/JSONKit.podspec.json').read
spec.gsub!(/https:\/\/github\.com\/johnezang\/JSONKit\.git/, fixture('integration/JSONKit').to_s)
spec.gsub!(pattern, replacement) if pattern && replacement
spec
......@@ -27,7 +40,7 @@ module Pod
# @return [Pathname]
#
def podspec_path
fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec'
fixture('spec-repos') + 'master/Specs/JSONKit/1.4/JSONKit.podspec.json'
end
#-------------------------------------------------------------------------#
......@@ -42,7 +55,7 @@ module Pod
end
it "lints the podspec during validation" do
podspec = stub_podspec(/s.name.*$/, 's.name = "TEST"')
podspec = stub_podspec(/.*name.*/, '"name": "TEST",')
file = write_podspec(podspec)
sut = Validator.new(file)
sut.quick = true
......@@ -60,7 +73,7 @@ module Pod
end
it "respects the only errors option" do
podspec = stub_podspec(/s.summary.*/, "s.summary = 'A short description of'")
podspec = stub_podspec(/.*summary.*/, '"summary": "A short description of",')
file = write_podspec(podspec)
sut = Validator.new(file)
sut.quick = true
......@@ -73,6 +86,8 @@ module Pod
it "handles symlinks" do
file = write_podspec(stub_podspec)
validator = Validator.new(file)
validator.quick = true
validator.stubs(:validate_url)
validator.validate
validator.validation_dir.should.be == Pathname.new("/private/tmp/CocoaPods/Lint")
end
......@@ -81,9 +96,163 @@ module Pod
#-------------------------------------------------------------------------#
describe "Extensive analysis" do
describe "URL validation" do
before do
@sut = Validator.new(podspec_path)
@sut.stubs(:install_pod)
@sut.stubs(:build_pod)
@sut.stubs(:check_file_patterns)
@sut.stubs(:tear_down_validation_environment)
WebMock::API.stub_request(:head, /not-found/).to_return(:status => 404)
WebMock::API.stub_request(:get, /not-found/).to_return(:status => 404)
end
describe "Homepage validation" do
it "checks if the homepage is valid" do
Specification.any_instance.stubs(:homepage).returns('http://banana-corp.local/not-found/')
@sut.validate
@sut.results.map(&:to_s).first.should.match /The URL (.*) is not reachable/
end
it "indicates if it was not able to validate the homepage" do
WebMock::API.stub_request(:head, 'banana-corp.local').to_raise(SocketError)
Specification.any_instance.stubs(:homepage).returns('http://banana-corp.local/')
@sut.validate
@sut.results.map(&:to_s).first.should.match /There was a problem validating the URL/
end
it "does not fail if the homepage redirects" do
WebMock::API.stub_request(:head, /redirect/).to_return(
:status => 301, :headers => { 'Location' => 'http://banana-corp.local/found/' } )
WebMock::API.stub_request(:head, /found/).to_return( :status => 200 )
Specification.any_instance.stubs(:homepage).returns('http://banana-corp.local/redirect/')
@sut.validate
@sut.results.length.should.equal 0
end
it "does not fail if the homepage does not support HEAD" do
WebMock::API.stub_request(:head, /page/).to_return( :status => 405 )
WebMock::API.stub_request(:get, /page/).to_return( :status => 200 )
Specification.any_instance.stubs(:homepage).returns('http://banana-corp.local/page/')
@sut.validate
@sut.results.length.should.equal 0
end
it "does not fail if the homepage errors on HEAD" do
WebMock::API.stub_request(:head, /page/).to_return( :status => 500 )
WebMock::API.stub_request(:get, /page/).to_return( :status => 200 )
Specification.any_instance.stubs(:homepage).returns('http://banana-corp.local/page/')
@sut.validate
@sut.results.length.should.equal 0
end
it "does not follow redirects infinitely" do
WebMock::API.stub_request(:head, /redirect/).to_return(
:status => 301,
:headers => { 'Location' => 'http://banana-corp.local/redirect/' } )
Specification.any_instance.stubs(:homepage).returns(
'http://banana-corp.local/redirect/')
@sut.validate
@sut.results.map(&:to_s).first.should.match /The URL \(.*\) is not reachable/
end
it "supports relative redirects" do
WebMock::API.stub_request(:head, /redirect/).to_return(
:status => 302,
:headers => { 'Location' => '/foo' })
WebMock::API.stub_request(:head, /foo/).to_return(
:status => 200 )
Specification.any_instance.stubs(:homepage).returns(
'http://banana-corp.local/redirect')
@sut.validate
@sut.results.length.should.equal 0
end
end
describe "Screenshot validation" do
before do
@sut.stubs(:validate_homepage)
WebMock::API.stub_request(:head, 'banana-corp.local/valid-image.png').to_return(:status => 200, :headers => { 'Content-Type' => 'image/png' })
end
it "checks if the screenshots are valid" do
Specification.any_instance.stubs(:screenshots).returns(['http://banana-corp.local/valid-image.png'])
@sut.validate
@sut.results.should.be.empty?
end
it "should fail if any of the screenshots URLS do not return an image" do
WebMock::API.stub_request(:head, 'banana-corp.local/').to_return(:status => 200)
Specification.any_instance.stubs(:screenshots).returns(['http://banana-corp.local/valid-image.png', 'http://banana-corp.local/'])
@sut.validate
@sut.results.map(&:to_s).first.should.match /The screenshot .* is not a valid image/
end
end
describe "social media URL validation" do
before do
@sut.stubs(:validate_homepage)
end
it "checks if the social media URL is valid" do
Specification.any_instance.stubs(:social_media_urlon_url).returns('http://banana-corp.local/')
WebMock::API.stub_request(:head, /banana-corp.local/).to_return(:status => 200)
@sut.validate
@sut.results.should.be.empty?
end
it "should fail validation if it wasn't able to validate the URL" do
Specification.any_instance.stubs(:social_media_url).returns('http://banana-corp.local/not-found/')
WebMock::API.stub_request(:head, /banana-corp.local/).to_return(:status => 404)
@sut.validate
@sut.results.map(&:to_s).first.should.match /The URL \(.*\) is not reachable/
end
end
describe "documentation URL validation" do
before do
@sut.stubs(:validate_homepage)
end
it "checks if the documentation URL is valid" do
Specification.any_instance.stubs(:documentation_url).returns('http://banana-corp.local/')
WebMock::API.stub_request(:head, /banana-corp.local/).to_return(:status => 200)
@sut.validate
@sut.results.should.be.empty?
end
it "should fail validation if it wasn't able to validate the URL" do
Specification.any_instance.stubs(:documentation_url).returns('http://banana-corp.local/not-found')
@sut.validate
@sut.results.map(&:to_s).first.should.match /The URL (.*) is not reachable/
end
end
describe "docset URL validation" do
before do
@sut.stubs(:validate_homepage)
end
it "checks if the docset URL is valid" do
Specification.any_instance.stubs(:docset_url).returns('http://banana-corp.local/')
WebMock::API.stub_request(:head, /banana-corp.local/).to_return(:status => 200)
@sut.validate
@sut.results.should.be.empty?
end
it "should fail validation if it wasn't able to validate the URL" do
Specification.any_instance.stubs(:docset_url).returns('http://banana-corp.local/not-found')
@sut.validate
@sut.results.map(&:to_s).first.should.match /The URL (.*) is not reachable/
end
end
end
it "respects the no clean option" do
file = write_podspec(stub_podspec)
sut = Validator.new(file)
sut.stubs(:validate_url)
sut.no_clean = true
sut.validate
sut.validation_dir.should.exist
......@@ -92,6 +261,7 @@ module Pod
it "builds the pod per platform" do
file = write_podspec(stub_podspec)
sut = Validator.new(file)
sut.stubs(:validate_url)
sut.expects(:install_pod).twice
sut.expects(:build_pod).twice
sut.expects(:check_file_patterns).twice
......@@ -100,6 +270,8 @@ module Pod
it "uses the deployment target of the specification" do
sut = Validator.new(podspec_path)
sut.stubs(:validate_url)
sut.stubs(:validate_screenshots)
podfile = sut.send(:podfile_from_spec, :ios, '5.0')
dependency = podfile.target_definitions['Pods'].dependencies.first
dependency.external_source.has_key?(:podspec).should.be.true
......@@ -107,6 +279,7 @@ module Pod
it "respects the local option" do
sut = Validator.new(podspec_path)
sut.stubs(:validate_url)
podfile = sut.send(:podfile_from_spec, :ios, '5.0')
deployment_target = podfile.target_definitions['Pods'].platform.deployment_target
deployment_target.to_s.should == "5.0"
......@@ -116,6 +289,7 @@ module Pod
sut = Validator.new(podspec_path)
sut.stubs(:check_file_patterns)
sut.stubs(:xcodebuild).returns("file.m:1:1: warning: direct access to objective-c's isa is deprecated")
sut.stubs(:validate_url)
sut.validate
first = sut.results.map(&:to_s).first
first.should.include "[xcodebuild]"
......@@ -123,22 +297,25 @@ module Pod
end
it "checks for file patterns" do
file = write_podspec(stub_podspec(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'wrong_paht.*'"))
file = write_podspec(stub_podspec(/.*source_files.*/, '"source_files": "wrong_paht.*",'))
sut = Validator.new(file)
sut.stubs(:build_pod)
sut.stubs(:validate_url)
sut.validate
sut.results.map(&:to_s).first.should.match /source_files.*did not match/
sut.result_type.should == :error
end
it "validates a podspec with dependencies" do
podspec = stub_podspec(/s.name.*$/, 's.name = "ZKit"')
podspec.gsub!(/s.requires_arc/, "s.dependency 'SBJson', '~> 3.2'\n s.requires_arc")
podspec.gsub!(/s.license.*$/, 's.license = "Public Domain"')
file = write_podspec(podspec, "ZKit.podspec")
podspec = stub_podspec(/.*name.*/, '"name": "ZKit",')
podspec.gsub!(/.*requires_arc.*/, '"dependencies": { "SBJson": [ "~> 3.2" ] }, "requires_arc": false')
podspec.gsub!(/.*license.*$/, '"license": "Public Domain",')
file = write_podspec(podspec, "ZKit.podspec.json")
spec = Specification.from_file(file)
sut = Validator.new(spec)
sut.stubs(:validate_url)
sut.stubs(:build_pod)
sut.validate
sut.validated?.should.be.true
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment