pathological 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pathological (0.2.3)
4
+ pathological (0.2.5)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
9
  fakefs (0.4.0)
10
10
  minitest (2.5.1)
11
+ rake (0.9.2.2)
11
12
  rr (1.0.3)
12
13
  scope (0.2.3)
13
14
  minitest
@@ -18,5 +19,6 @@ PLATFORMS
18
19
  DEPENDENCIES
19
20
  fakefs
20
21
  pathological!
22
+ rake
21
23
  rr (>= 1.0.3)
22
24
  scope (>= 0.2.3)
data/README.md CHANGED
@@ -32,16 +32,23 @@ Getting started with pathological is easy. First, make a file called `Pathfile`
32
32
 
33
33
  Now require the gem at the start of any executable ruby file:
34
34
 
35
- #!/usr/bin/env ruby
35
+ ``` ruby
36
+ #!/usr/bin/env ruby
36
37
 
37
- require "rubygems" # If you're using 1.8
38
- require "pathological"
39
- # other requires...
38
+ require "bundler/setup" # If you're using bundler
39
+ require "pathological"
40
+
41
+ # other requires...
42
+ ```
40
43
 
41
44
  Now your project root will be in your load path. If your project has, for example, `lib/foo.rb`, then `require
42
45
  lib/foo` will work in any of your ruby files. This works because when Pathological is required it will search
43
46
  up the directory tree until it finds a `Pathfile`. (It will raise an error if one cannot be found).
44
47
 
48
+ Note that Pathological should be the first require in your main file so that it will be loaded first. An
49
+ exception to this is when you're using Bundler, in which case you should `require bundler/setup` before
50
+ Pathological (and of course you should have `gem "pathological"` in your `Gemfile`).
51
+
45
52
  `Pathfile`s should be kept in version control.
46
53
 
47
54
  Adding other paths to your load path
@@ -70,11 +77,12 @@ and that `Pathfile` contains the following:
70
77
 
71
78
  Then inside `run_my_project.rb`:
72
79
 
73
- require "rubygems"
74
- require "pathological"
75
- require "foo"
76
- require "common"
77
- # ...
80
+ ``` ruby
81
+ require "pathological"
82
+ require "foo"
83
+ require "common"
84
+ # ...
85
+ ```
78
86
 
79
87
  Installation
80
88
  ------------
@@ -120,15 +128,19 @@ should be avoided if possible.
120
128
 
121
129
  There are two ways to specify modes. First, you can enable any modes you want using the Pathological API:
122
130
 
123
- require "pathological/base"
124
- Pathological.debug_mode
125
- Pathological.parentdir_mode
126
- Pathological.add_paths!
131
+ ``` ruby
132
+ require "pathological/base"
133
+ Pathological.debug_mode
134
+ Pathological.parentdir_mode
135
+ Pathological.add_paths!
136
+ ```
127
137
 
128
138
  A quicker way is also provided: if you only need to use one special mode, then there is a dedicated file you
129
139
  can require:
130
140
 
131
- require "pathological/bundlerize"
141
+ ``` ruby
142
+ require "pathological/bundlerize"
143
+ ```
132
144
 
133
145
  Public API
134
146
  ----------
@@ -136,10 +148,11 @@ Public API
136
148
  For even more configurable custom integration with Pathological, a public API is provided. See the generated
137
149
  documentation for details on the following public methods:
138
150
 
139
- Pathological#add_paths!
140
- Pathological#find_load_paths
141
- Pathological#find_pathfile
142
- Pathological#reset!
151
+ * `Pathological#add_paths!`
152
+ * `Pathological#find_load_paths`
153
+ * `Pathological#find_pathfile`
154
+ * `Pathological#reset!`
155
+ * `Pathological#copy_outside_paths!`
143
156
 
144
157
  Authors
145
158
  -------
@@ -149,6 +162,7 @@ Pathological was written by the following Ooyala engineers:
149
162
  * [Daniel MacDougall](mailto:dmac@ooyala.com)
150
163
  * [Caleb Spare](mailto:caleb@ooyala.com)
151
164
  * [Sami Abu-El-Haija](mailto:sami@ooyala.com)
165
+ * [Evan Chan](mailto:ev@ooyala.com)
152
166
 
153
167
  Credits
154
168
  -------
data/Rakefile CHANGED
@@ -1,2 +1,14 @@
1
1
  require "bundler"
2
+ require "rake/testtask"
3
+
2
4
  Bundler::GemHelper.install_tasks
5
+
6
+ task :test => ["test:units"]
7
+
8
+ namespace :test do
9
+ Rake::TestTask.new(:units) do |task|
10
+ task.libs << "test"
11
+ task.test_files = FileList["test/unit/**/*_test.rb"]
12
+ end
13
+ end
14
+
@@ -76,6 +76,57 @@ module Pathological
76
76
  end
77
77
  end
78
78
 
79
+ # Copies directories in pathfile to a destination, such that the destination has no references to
80
+ # directories outside of the destination in the load path.
81
+ #
82
+ # Hierarchy of destination directory:
83
+ # destination/
84
+ # Pathfile # new paths
85
+ # dependency_directory/
86
+ # dependency1 # Copied from original location
87
+ #
88
+ # This is very useful for deployment, for example.
89
+ #
90
+ # @param [String] copy_outside_paths the directory to stage dependencies in
91
+ # @param [String] dependency_directory the subdir within destination to put dependencies in
92
+ #
93
+ # TODO(ev): Break this function up into a set of more functional primitives
94
+ def self.copy_outside_paths!(destination, dependency_directory = "pathological_dependencies")
95
+ saved_exclude_root = @@exclude_root
96
+ begin
97
+ self.excluderoot_mode
98
+ pathfile = self.find_pathfile
99
+ # Nothing to do if there's no Pathfile
100
+ return unless pathfile && File.file?(pathfile)
101
+
102
+ foreign_paths = self.find_load_paths(pathfile).uniq
103
+ return if foreign_paths.empty?
104
+
105
+ path_root = File.join(destination, dependency_directory)
106
+ FileUtils.mkdir_p path_root
107
+
108
+ # Copy in each path and save the relative paths to write to the rewritten Pathfile. We copy each unique
109
+ # path into the folder not as the basename, but as the longest suffix of the path necessary to make it
110
+ # unique. (Otherwise this won't work if you have two entries with the same basename in the Pathfile,
111
+ # such as "foo/lib" and "bar/lib".)
112
+ common_prefix = find_longest_common_prefix(foreign_paths)
113
+ new_pathfile_paths = foreign_paths.map do |foreign_path|
114
+ path_short_name = foreign_path.gsub(/^#{common_prefix}/, "")
115
+ symlinked_name = File.join(path_root, path_short_name)
116
+ FileUtils.mkdir_p File.split(symlinked_name)[0]
117
+ debug "About to move #{foreign_path} to #{symlinked_name}..."
118
+ copy_directory(foreign_path, symlinked_name)
119
+ File.join(dependency_directory, path_short_name)
120
+ end
121
+ # Overwrite the Pathfile with the new relative paths.
122
+ File.open(File.join(destination, "Pathfile"), "w") do |file|
123
+ new_pathfile_paths.each { |path| file.puts path }
124
+ end
125
+ ensure
126
+ @@exclude_root = saved_exclude_root
127
+ end
128
+ end
129
+
79
130
  # Convenience functions for the various modes in which Pathological may run.
80
131
 
81
132
  def self.debug_mode; @@debug = true; end
@@ -155,9 +206,35 @@ module Pathological
155
206
  @@exclude_root ? paths.reject { |path| File.expand_path(path) == File.expand_path(root) } : paths
156
207
  end
157
208
 
158
- # Searches the call stack for the file that required pathological.
159
- # If no file can be found, falls back to the currently executing file ($0).
160
- # This handles the case where the app was launched by another executable (rake, thin, rackup, etc.)
209
+ # Find the longest common path prefix amongst a list of paths
210
+ #
211
+ # @private
212
+ # @param [List<String>] a list of paths
213
+ # @return [String] the longest common prefix, or "/"
214
+ def self.find_longest_common_prefix(paths)
215
+ if paths.size == 1
216
+ common_prefix = File.split(paths[0])[0]
217
+ else
218
+ common_prefix = "/"
219
+ paths[0].split("/").reject(&:empty?).each do |part|
220
+ new_prefix = "#{common_prefix}#{part}/"
221
+ break unless paths.all? { |path| path.start_with? new_prefix }
222
+ common_prefix = new_prefix
223
+ end
224
+ end
225
+ common_prefix
226
+ end
227
+
228
+ # Copies a directory and all its symlinks to a destination.
229
+ # @private
230
+ def self.copy_directory(source, dest)
231
+ rsync_command = "rsync -r --archive --links --copy-unsafe-links --delete #{source}/ '#{dest}'"
232
+ debug `#{rsync_command}`
233
+ end
234
+
235
+ # Searches the call stack for the file that required pathological. If no file can be found, falls back to
236
+ # the currently executing file ($0). This handles the case where the app was launched by another executable
237
+ # (rake, thin, rackup, etc.)
161
238
  #
162
239
  # @return [String] name of file requiring pathological, or the currently executing file.
163
240
  def self.requiring_filename
@@ -173,7 +250,7 @@ module Pathological
173
250
  requiring_file ? requiring_file.match(/(.+):\d+/)[1] : $0 rescue $0
174
251
  end
175
252
 
176
- private_class_method :debug, :real_path, :parse_pathfile
253
+ private_class_method :debug, :real_path, :parse_pathfile, :find_longest_common_prefix, :copy_directory
177
254
 
178
255
  # Reset options
179
256
  Pathological.reset!
@@ -1,3 +1,3 @@
1
1
  module Pathological
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.required_rubygems_version = Gem::Requirement.new(">=0") if s.respond_to? :required_rubygems_version=
11
11
  s.specification_version = 2 if s.respond_to? :specification_version=
12
12
 
13
- s.authors = "Daniel MacDougall", "Caleb Spare"
14
- s.email = "dmac@ooyala.com", "caleb@ooyala.com"
13
+ s.authors = "Daniel MacDougall", "Caleb Spare", "Evan Chan"
14
+ s.email = "dmac@ooyala.com", "caleb@ooyala.com", "ev@ooyala.com"
15
15
  s.homepage = "http://www.ooyala.com"
16
16
  s.rubyforge_project = "pathological"
17
17
 
@@ -28,4 +28,5 @@ Gem::Specification.new do |s|
28
28
  s.add_development_dependency "rr", ">= 1.0.3"
29
29
  s.add_development_dependency "scope", ">= 0.2.3"
30
30
  s.add_development_dependency "fakefs"
31
+ s.add_development_dependency "rake"
31
32
  end
@@ -210,6 +210,45 @@ module Pathological
210
210
  assert_load_path ["/foo/bar"]
211
211
  end
212
212
  end
213
+
214
+ context "#copy_outside_paths!" do
215
+ setup do
216
+ @destination = "/tmp/staging"
217
+ @pathfile = "/Pathfile"
218
+ FileUtils.cd "/"
219
+ FileUtils.mkdir_p @destination
220
+ @source_paths = ["/src/github1", "/src/moofoo"]
221
+ @source_paths.each { |src_dir| FileUtils.mkdir_p src_dir }
222
+ end
223
+
224
+ should "return immediately if there is no Pathfile" do
225
+ mock(Pathological).find_pathfile { nil }
226
+ Pathological.copy_outside_paths! @destination
227
+ refute File.directory?(File.join(@destination, "pathological_dependencies"))
228
+ end
229
+
230
+ should "return immediately if Pathfile is empty" do
231
+ File.open(@pathfile, "w") { |f| f.puts "\n# What the heck is this file?\n\n" }
232
+ Pathological.copy_outside_paths! @destination
233
+ refute File.directory?(File.join(@destination, "pathological_dependencies"))
234
+ end
235
+
236
+ should "copy source dirs as links and rewrite Pathfile" do
237
+ File.open(@pathfile, "w") { |f| f.puts @source_paths.join("\n") }
238
+
239
+ final_path = File.join(@destination, "pathological_dependencies")
240
+ @source_paths.each do |source_path|
241
+ mock(Pathological).copy_directory(source_path, final_path + source_path.gsub("/src", "")).once
242
+ end
243
+ Pathological.copy_outside_paths! @destination
244
+
245
+ assert File.directory?(final_path)
246
+ destination_paths = @source_paths.map do |source_path|
247
+ "pathological_dependencies#{source_path.gsub("/src", "")}"
248
+ end
249
+ assert_equal destination_paths, File.read(File.join(@destination, "Pathfile")).split("\n")
250
+ end
251
+ end
213
252
  end
214
253
  end
215
254
  end
metadata CHANGED
@@ -1,20 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pathological
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Daniel MacDougall
9
9
  - Caleb Spare
10
+ - Evan Chan
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2011-09-29 00:00:00.000000000Z
14
+ date: 2012-09-04 00:00:00.000000000Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: rr
17
- requirement: &2153778480 !ruby/object:Gem::Requirement
18
+ requirement: &27117160 !ruby/object:Gem::Requirement
18
19
  none: false
19
20
  requirements:
20
21
  - - ! '>='
@@ -22,10 +23,10 @@ dependencies:
22
23
  version: 1.0.3
23
24
  type: :development
24
25
  prerelease: false
25
- version_requirements: *2153778480
26
+ version_requirements: *27117160
26
27
  - !ruby/object:Gem::Dependency
27
28
  name: scope
28
- requirement: &2153778020 !ruby/object:Gem::Requirement
29
+ requirement: &27091120 !ruby/object:Gem::Requirement
29
30
  none: false
30
31
  requirements:
31
32
  - - ! '>='
@@ -33,10 +34,10 @@ dependencies:
33
34
  version: 0.2.3
34
35
  type: :development
35
36
  prerelease: false
36
- version_requirements: *2153778020
37
+ version_requirements: *27091120
37
38
  - !ruby/object:Gem::Dependency
38
39
  name: fakefs
39
- requirement: &2153777640 !ruby/object:Gem::Requirement
40
+ requirement: &27090740 !ruby/object:Gem::Requirement
40
41
  none: false
41
42
  requirements:
42
43
  - - ! '>='
@@ -44,13 +45,25 @@ dependencies:
44
45
  version: '0'
45
46
  type: :development
46
47
  prerelease: false
47
- version_requirements: *2153777640
48
+ version_requirements: *27090740
49
+ - !ruby/object:Gem::Dependency
50
+ name: rake
51
+ requirement: &27090280 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *27090280
48
60
  description: ! " Pathological provides a way to manage a project's require paths
49
61
  by using a small config file that\n indicates all directories to include in the
50
62
  load path.\n"
51
63
  email:
52
64
  - dmac@ooyala.com
53
65
  - caleb@ooyala.com
66
+ - ev@ooyala.com
54
67
  executables: []
55
68
  extensions: []
56
69
  extra_rdoc_files: []
@@ -71,8 +84,7 @@ files:
71
84
  - lib/pathological/parentdir.rb
72
85
  - lib/pathological/version.rb
73
86
  - pathological.gemspec
74
- - test/pathological/base_test.rb
75
- - test/unit.watchr.rb
87
+ - test/unit/pathological/base_test.rb
76
88
  homepage: http://www.ooyala.com
77
89
  licenses: []
78
90
  post_install_message:
@@ -93,8 +105,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
105
  version: '0'
94
106
  requirements: []
95
107
  rubyforge_project: pathological
96
- rubygems_version: 1.8.7
108
+ rubygems_version: 1.8.10
97
109
  signing_key:
98
110
  specification_version: 2
99
111
  summary: A nice way to manage your project's require paths.
100
112
  test_files: []
113
+ has_rdoc:
@@ -1,10 +0,0 @@
1
- # Watchr script for unit tests
2
-
3
- def run_test(test)
4
- system("bundle exec ruby #{test}")
5
- end
6
-
7
- watch(/^test\/.*_test\.rb/) { |md| run_test(md[0]) }
8
- watch(/^lib\/(.*)\.rb/) { |md| run_test("test/#{md[1]}_test.rb") }
9
-
10
- Signal.trap("INT") { abort("\n") }