pathological 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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") }