laravel 0.2.1 → 0.3.2

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,6 +1,7 @@
1
1
  require "aruba/cucumber"
2
2
  require "laravel"
3
3
 
4
+ # After a scenario has been ran, deleted the files we may have created.
4
5
  After do
5
6
  test_directory = File.expand_path(File.join(File.dirname(__FILE__), %w[ .. .. tmp aruba]))
6
7
  FileUtils.rm_rf(File.join(test_directory, "my_app"))
@@ -1,40 +1,79 @@
1
- module LaravelHelpers
2
- TestDirectory = File.expand_path(File.join(File.dirname(__FILE__), %w[ .. .. tmp aruba]))
1
+ module Laravel
2
+ # a means to test the gem
3
+ class AppTests
4
+ attr_reader :app, :app_dir, :repo, :aruba
3
5
 
4
- # get the relative path of a directory relative to the temporary path aruba creates
5
- def get_relative_path_to_test_directory(dir, relative_to = nil)
6
- relative_to = TestDirectory unless relative_to
7
- File.expand_path(dir, relative_to)
8
- end
6
+ # create a new object that handles the tests for us
7
+ #
8
+ # ==== Parameters
9
+ # +dir+ :: directory of the application - can be relative path or absolute path.
10
+ # +repo+ :: repository URL/directory for source
11
+ #
12
+ def initialize(dir = nil, repo = nil)
13
+ @repo = repo
14
+ @aruba = File.expand_path(File.join(File.dirname(__FILE__), %w[ .. .. tmp aruba]))
15
+
16
+ # Store absolute path to the directory
17
+ @app_dir = dir || Dir.pwd
18
+ convert_to_relative_path
19
+
20
+ options = {
21
+ :force => false, :quiet => false,
22
+ :perms => true, :source => get_source_url
23
+ }
9
24
 
10
- # get the url to the repository by its name
11
- def get_test_repo_url(repo = nil)
12
- case repo
13
- when nil, "official", "default" then Laravel::OfficialRepository
14
- when "pastes" then "http://github.com/laravel/pastes"
15
- when "non_laravel" then "http://github.com/github/gitignore"
16
- else repo
25
+ # create a new Laravel App instance for given options
26
+ @app = Laravel::App.new(@app_dir, options)
17
27
  end
18
- end
19
28
 
20
- # get the full path to the repository by its name
21
- def get_test_repo_path(repo = nil, repo_url = nil)
22
- repo_url = get_test_repo_url(repo) unless repo_url
23
- Laravel::crypted_path(repo_url)
24
- end
29
+ # get the relative path of a directory relative to the temporary path aruba creates
30
+ #
31
+ # ==== Parameters
32
+ # +relative_to+ :: Path to use as base directory, when converting to relative path.
33
+ # By default, it is the path to the aruba tmp directory
34
+ #
35
+ def convert_to_relative_path(relative_to = nil)
36
+ relative_to = @aruba unless relative_to
37
+ @app_dir = File.expand_path(@app_dir, relative_to)
38
+ end
25
39
 
26
- # checks if the configuration file contains a particular string
27
- def check_config_file_for_string(search, dir)
28
- dir = get_relative_path_to_test_directory(dir)
29
- config_file = File.join(dir, %w[ application config application.php ])
30
- raise RSpec::Expectations::ExpectationNotMetError unless File.readlines(config_file).grep(/#{search}/).any?
31
- end
40
+ # get the url to a repository by a given alias/name
41
+ #
42
+ # ==== Return
43
+ # +string+ :: URL for the repository
44
+ #
45
+ def get_source_url
46
+ case @repo
47
+ when nil, "", "official", "default" then Laravel::App::LaravelRepo
48
+ when "pastes" then "http://github.com/laravel/pastes"
49
+ when "non_laravel" then "http://github.com/github/gitignore"
50
+ else @repo
51
+ end
52
+ end
32
53
 
33
- # raises an error based on a condition and negation
34
- # if negation is not supplied, simply raises an error if condition is not true
35
- def raise_error_based_on_condition(condition, negate = nil)
36
- raise RSpec::Expectations::ExpectationNotMetError if condition == !negate.nil?
54
+ # checks if the configuration file contains a particular string
55
+ #
56
+ # ==== Parameters
57
+ # +search+ :: the search term/regex pattern to look for
58
+ #
59
+ # ==== Return
60
+ # +boolean+:: true, if the search term was found in the configuration file.
61
+ #
62
+ def validate_configuration(search)
63
+ raise_error? File.readlines(@app.config_file).grep(Regexp.new search).any?
64
+ end
65
+
66
+ # raises an error based on a condition and negation
67
+ # if negation is not supplied, simply raises an error if condition is not true
68
+ #
69
+ # ==== Parameters
70
+ # +condition+ :: a condition to check against - if +negate+ is not provided,
71
+ # this condition raises an error if it evaluates to false.
72
+ # +negate+ :: negate the default behaviour
73
+ def raise_error?(condition, negate = nil)
74
+ raise RSpec::Expectations::ExpectationNotMetError if condition == !negate.nil?
75
+ end
37
76
  end
38
77
  end
39
78
 
40
- World(LaravelHelpers)
79
+ World(Laravel)
@@ -13,7 +13,7 @@ Gem::Specification.new do |gem|
13
13
  gem.homepage = "https://github.com/nikhgupta/laravel"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.executables = ["laravel"]
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
@@ -3,7 +3,7 @@ require "thor"
3
3
 
4
4
  # require laravel files
5
5
  require "laravel/version"
6
- require "laravel/info"
7
- require "laravel/helpers"
8
- require "laravel/manage"
9
- require "laravel/create"
6
+ require "laravel/app_support"
7
+ require "laravel/app"
8
+ require "laravel/configuration"
9
+ require "laravel/installer"
@@ -0,0 +1,95 @@
1
+ module Laravel
2
+ # This class provides a means to create new applications based on the Laravel
3
+ # framework. Most of the methods used here have been defined in the
4
+ # AppSupport module, which is being included as a mixin here.
5
+ #
6
+ class App
7
+ # include the AppSupport module which has all the methods defined.
8
+ include Laravel::AppSupport
9
+
10
+ # these attributes must be available as: object.attribute
11
+ attr_reader :cache_folder, :laravel_repo, :app_path, :source, :cache, :options
12
+
13
+ # the path to the folder where the sources will be locally cached.
14
+ CacheFolder = File.expand_path(File.join(ENV['HOME'], %w[ .laravel repos ]))
15
+
16
+ # the official Laravel repository URL which is also the default source for us.
17
+ LaravelRepo = "http://github.com/laravel/laravel.git"
18
+
19
+ # This method initializes a new App object for us, on which we can apply
20
+ # our changes. Logically, this new App object represents an application
21
+ # based on Laravel.
22
+ #
23
+ # ==== Parameters
24
+ # +app_path+ :: The path to the Laravel based application. This can either
25
+ # be a relative path to the current directory, or the absolute path. If
26
+ # +app_path+ is not supplied, we assume current directory.
27
+ #
28
+ # +options+ :: A hash of options for this application. This hash can be
29
+ # created manually, but more closely resembles the options choosen by the
30
+ # user and forwarded by the Thor to us.
31
+ #
32
+ def initialize(app_path = nil, options = nil)
33
+ app_path = Dir.pwd if not app_path or app_path.empty?
34
+ @app_path = File.expand_path(app_path)
35
+
36
+ @options = options
37
+
38
+ @source = options[:source] if options
39
+ @source = LaravelRepo if not @source or @source.empty?
40
+
41
+ @cache = source_is_local? ? @source : cache_directory
42
+ end
43
+
44
+ # This method creates a new Laravel based application for us. This method
45
+ # is invoked by the 'new' task. It first checks if we can create the
46
+ # application in the specified directory, then updates/downloads the local
47
+ # cache for the given source, and then copies over the files from this
48
+ # cache to the specified directory. Finally, it checks if we have a working
49
+ # Laravel application at which point it either raises and error and cleans
50
+ # up, or configures the application and installs tasks/bundles, as
51
+ # requested.
52
+ #
53
+ def create
54
+ # check if we are missing the required force
55
+ required_force_is_missing?
56
+
57
+ # apply some force, when we are boosted with one
58
+ apply_force
59
+
60
+ # download or update local cache
61
+ download_or_update_local_cache
62
+
63
+ # copy the framework files from the cache
64
+ copy_over_cache_files
65
+
66
+ # make necessary changes for the new app, if we were successful in download
67
+ # otherwise, remove the downloaded source
68
+ if has_laravel?
69
+ say_success "Cloned Laravel repository."
70
+ configure_from_options
71
+ install_from_options
72
+ say_success "Hurray! Your Laravel application has been created!"
73
+ else
74
+ say_failed "Downloaded source is not Laravel framework or a possible fork."
75
+ show_info "Cleaning up.."
76
+ clean_up
77
+ show_error "Specified Laravel source is corrupt!"
78
+ end
79
+ end
80
+
81
+ # This method installs the required tasks/bundles by the user.
82
+ # It does so by invoking the 'from_options' method of the Installer class.
83
+ def install_from_options
84
+ install = Installer.new(@app_path, @options)
85
+ install.from_options
86
+ end
87
+
88
+ # This method configures the application as required by the user.
89
+ # It does so by invoking the 'from_options' method of the Configuration class.
90
+ def configure_from_options
91
+ config = Configuration.new(@app_path, @options)
92
+ config.update_from_options
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,282 @@
1
+ require 'digest/md5'
2
+
3
+ module Laravel
4
+ # various methods that help with various classes defined for the Laravel module
5
+ module AppSupport
6
+
7
+ # convert a string to MD5 hash - useful to generate quick random strings.
8
+ #
9
+ # ==== Parameters
10
+ # +string+ :: optional, the input string to be hashed
11
+ # :: a random string will be used for hashing, if this string is not provided
12
+ #
13
+ # ==== Return
14
+ # +string+ :: a 32-character long MD5'ed string
15
+ #
16
+ def make_md5(string = nil)
17
+ string ||= (0...32).map{ ('a'..'z').to_a[rand(26)] }.join
18
+ (Digest::MD5.new << string).to_s
19
+ end
20
+
21
+ # Return the path to the local cache directory for a given Source
22
+ #
23
+ # ==== Return
24
+ # +string+ :: Filepath to the local cache directory
25
+ #
26
+ def cache_directory
27
+ File.join(Laravel::App::CacheFolder, make_md5(@source))
28
+ end
29
+
30
+ # Check whether the app directory is the current directory.
31
+ # This is useful to know if we are creating the new application
32
+ # in the current directory.
33
+ #
34
+ # ==== Return
35
+ # +boolean+ :: True, if the app directory is the current directory.
36
+ #
37
+ def current_directory?
38
+ File.directory?(@app_path) and (@app_path == File.expand_path(Dir.pwd))
39
+ end
40
+
41
+ # Check whether the app directory is empty?
42
+ # This is useful to know if we are trying to create the new application
43
+ # in an empty directory or not, so that we may know if we need to create
44
+ # this application forcefully?
45
+ #
46
+ # ==== Return
47
+ # +boolean+ :: True, if the app directory is an empty one.
48
+ #
49
+ def empty_directory?
50
+ File.directory?(@app_path) and (Dir.entries(@app_path).size == 2)
51
+ end
52
+
53
+ # Check whether the specified source is a local directory or a URL?
54
+ #
55
+ # ==== Return
56
+ # +boolean+ :: True, if the source is a local directory.
57
+ #
58
+ def source_is_local?
59
+ File.directory?(@source)
60
+ end
61
+
62
+ # Merge the specified options with the options specified on the command line.
63
+ #
64
+ # ==== Parameters
65
+ # +options+ :: hash of options passed at the command line
66
+ #
67
+ # ==== Return
68
+ # +hash+ :: hash of merged options
69
+ #
70
+ def merge_options(options)
71
+ @options.merge!(options)
72
+ end
73
+
74
+ # Return the path to the configuration file for the current application
75
+ #
76
+ # ==== Return
77
+ # +string+ :: path to the configuration file
78
+ #
79
+ def config_file
80
+ File.join(@app_path, %w[ application config application.php ])
81
+ end
82
+
83
+ # Return the path to a tasks file by its name
84
+ #
85
+ # ==== Parameters
86
+ # +name+ :: string - name of the tasks file
87
+ #
88
+ # ==== Return
89
+ # +string+ :: path to the tasks file
90
+ #
91
+ def tasks_file(name)
92
+ File.expand_path(File.join(@app_path, %w[ application tasks ], name))
93
+ end
94
+
95
+ # Download a given resource at a particular path
96
+ #
97
+ # ==== Parameters
98
+ # +path+ :: Path where the downloaded content will be saved.
99
+ # This can either be the path to a single file or a directory.
100
+ # If this is a directory, git will be used to download the source,
101
+ # otherwise, curl will be used for the same. Therefore, please, make
102
+ # sure that the source is a git repository when +path+ is a directory,
103
+ # and that the source is an online file when +path+ is a file.
104
+ # +source+ :: Source URL/directory from where the content of the resource will be
105
+ # downloaded. Please, read information about +path+
106
+ #
107
+ # ==== Return
108
+ # +boolean+ :: true, if the resource was downloaded successfully.
109
+ #
110
+ def download_resource(path, source, using)
111
+ using = "wget" if using == "curl" and `which curl`.empty? and not `which wget`.empty?
112
+ case using
113
+ when "git" then system("git clone -q #{source} #{path}")
114
+ when "curl" then system("curl -s #{source} > #{path}")
115
+ when "wget" then system("wget #{source} -O #{path}")
116
+ else false
117
+ end
118
+ end
119
+
120
+ # check if laravel framework exists in the current application's directory
121
+ # currently, this is performed by looking for the presence of 'artisan' file
122
+ # and the 'laravel' subdirectory.
123
+ #
124
+ # ==== Return
125
+ # +boolean+ :: true, if laravel framework exists
126
+ #
127
+ def has_laravel?
128
+ laravel_exists_in_directory?(@app_path)
129
+ end
130
+
131
+ # check if the cache exists for the source specified by the current
132
+ # application's directory this further makes sure that the cache really has
133
+ # laravel framework as we would expect it to
134
+ #
135
+ # ==== Return
136
+ # +boolean+ :: true, if the cache exists
137
+ #
138
+ def has_cache?
139
+ laravel_exists_in_directory?(@cache)
140
+ end
141
+
142
+ # check if laravel framework exists in a specified directory
143
+ # this method is in turn called by the instance methods: 'has_cache?'
144
+ # and the 'has_laravel?'
145
+ #
146
+ # ==== Parameters
147
+ # +directory+ :: directory to check for the existance of laravel framework
148
+ # this can be the relative path to the current app directory
149
+ # or the absolute path of the directory.
150
+ #
151
+ # ==== Return
152
+ # +boolean+ :: true, if laravel exists in the given directory
153
+ #
154
+ def laravel_exists_in_directory?(directory = "")
155
+ return false unless directory
156
+ directory = File.expand_path(directory, @app_path)
157
+ return false unless File.exists? File.join(directory, "artisan")
158
+ return false unless File.directory? File.join(directory, "laravel")
159
+ true
160
+ end
161
+
162
+ # This method first checks if the given application path requires
163
+ # the 'force' option, and then checks if the 'force' option is provided
164
+ # by the user.
165
+ #
166
+ # Whether the path requires 'force' is determined as:
167
+ # -- it is not the current directory
168
+ # -- it is the current directory but is empty
169
+ #
170
+ # ==== Return
171
+ # +error+ :: raises an error, if the 'force' parameter is required!!
172
+ #
173
+ def required_force_is_missing?
174
+ # we need force if path exists and is not the current directory
175
+ check_force = (File.exists?(@app_path) and not current_directory?)
176
+ # we need force if path is current directory but is not empty
177
+ check_force ||= (current_directory? and not empty_directory?)
178
+ # raise an error when we need to force and we have not been supplied with enforcements
179
+ show_error "required force is missing! please, provide enforcements!" if check_force and not @options[:force]
180
+ end
181
+
182
+ # Depending on whether the 'force' parameter is provided, this method
183
+ # removes all the files in the directory specified by the application path,
184
+ # if the directory exists. Further, if the directory doesn't exist, it
185
+ # tries to create the directory specified by the application path.
186
+ #
187
+ def apply_force
188
+ show_info "Creating application forcefully!" if @options[:force]
189
+ FileUtils.rm_rf("#{@app_path}/.", :secure => true) if File.exists?(@app_path) and @options[:force]
190
+ FileUtils.mkdir_p @app_path
191
+ end
192
+
193
+ # This method downloads or updates the local cache for the current source.
194
+ #
195
+ # If the source is a directory on this machine, it will simply not do
196
+ # anything since that can interfere with an offline installation, and the
197
+ # user must update the source manually in this case.
198
+ #
199
+ # Otherwise, it uses git to update or download the source as required and
200
+ # caches it locally.
201
+ #
202
+ def download_or_update_local_cache
203
+ return if source_is_local?
204
+ show_error "git is required!" if `which git`.empty?
205
+ FileUtils.mkdir_p @cache
206
+ Dir.chdir(@cache) do
207
+ if has_cache?
208
+ show_info "Repository exists in local cache.."
209
+ show_info "Updating local cache.."
210
+ `git pull &>/dev/null`
211
+ else
212
+ show_info "Downloading repository to local cache.."
213
+ `git clone #{@source} . &>/dev/null`
214
+ end
215
+ end
216
+ end
217
+
218
+ # This method copies the files from the local cache to the directory of the
219
+ # application.
220
+ #
221
+ def copy_over_cache_files
222
+ FileUtils.cp_r "#{@cache}/.", @app_path
223
+ end
224
+
225
+ # This method updates the permissions on the storage/ directory inside
226
+ # the newly created application. This method does not have a separate exposed
227
+ # call from the CLI. This can be skipped by passing '--no-perms' for the 'new'
228
+ # command.
229
+ #
230
+ def update_permissions_on_storage
231
+ if @options[:perms]
232
+ response = system("chmod -R o+w #{File.join(@app_path, 'storage')}")
233
+ if response
234
+ say_success "Updated permissions on storage/ directory."
235
+ else
236
+ say_failed "Could not update permissions on storage/ directory."
237
+ end
238
+ end
239
+ end
240
+
241
+ # Once, we are done with the intallation, and an error occurs, this method handles
242
+ # the clean_up routine by removing the application directory we created, as well as
243
+ # the local cache for the source, that may exist.
244
+ #
245
+ # Keeping the local cache does not make sense, since we anyways can not create
246
+ # applications based on these 'corrupt' repositories.
247
+ def clean_up
248
+ FileUtils.rm_rf "#{@app_path}" unless current_directory?
249
+ FileUtils.rm_rf "#{@cache}"
250
+ end
251
+
252
+ # This method, simply, imitates the 'say' method that the Thor gem provides us.
253
+ # I preferred to use this method, since it gives us a very nice UI at the CLI :)
254
+ #
255
+ def say(status, message = "", log_status = true)
256
+ shell = Thor::Shell::Color.new
257
+ log_status = false if @options and @options[:quiet]
258
+ shell.say_status(status, message, log_status)
259
+ end
260
+
261
+ # Show some information to the user in Cyan.
262
+ def show_info(message)
263
+ say "Information", message, :cyan
264
+ end
265
+
266
+ # Show a success message to the user in Green.
267
+ def say_success(message)
268
+ say "Success", message, :green
269
+ end
270
+
271
+ # Show a failed message to the user in Yellow.
272
+ def say_failed(message)
273
+ self.say "Failed!!", message, :yellow
274
+ end
275
+
276
+ # Show an error the user in Red, and exit the script, since this is an error!
277
+ def show_error(message)
278
+ self.say "!!ERROR!!", message, :red
279
+ exit
280
+ end
281
+ end
282
+ end