Class: SC::Project

Inherits:
Object
  • Object
show all
Defined in:
lib/sproutcore/models/project.rb

Overview

A project describes a collection of targets that you can build. Normally you instantiate a project by calling Project.load() method. You should pass in the path of the project and the project type. The project type will determine the namespace used in the buildfile to detect and load tasks.

Examples

Load a SproutCore-style project:

Project.load('myproject', :sproutcore)

Load a standard gcc-build project:

Project.load('myproject', :cc)

How a Project is Loaded

When you load a project, here is what happens:

  1. Locate and load Buildfiles, if any are found

  2. Run project_type:target:find for all targets defined for the project.

    this will locate and define the targets for the project

  3. If you request a build of a particular resource, a manifest will be built for the target. This manifest contains a series of rules that can be invoked in order to build the named resource.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_root, opts = {}) ⇒ Project

When a new project is created, you may optionally pass either a :parent option or a :paths options. If you pass the paths option, then this class will search the paths for projects and initialize them as parent projects to this one.

If you pass a parent project, then this project will start out with a clone of the parent project’s buildfile and targets.



57
58
59
60
61
# File 'lib/sproutcore/models/project.rb', line 57

def initialize(project_root, opts ={})
  @project_root = project_root
  @parent_project = opts[:parent]
  @buildfile = @targets = nil
end

Instance Attribute Details

#parent_projectObject (readonly)

Parent project this project shoud inherit build rules and targets from



43
44
45
# File 'lib/sproutcore/models/project.rb', line 43

def parent_project
  @parent_project
end

#project_rootObject (readonly)

the path of this project



40
41
42
# File 'lib/sproutcore/models/project.rb', line 40

def project_root
  @project_root
end

Class Method Details

.load(project_root, opts = {}) ⇒ Object

Returns a new project loaded from the specified path



82
83
84
# File 'lib/sproutcore/models/project.rb', line 82

def self.load(project_root, opts={})
  new project_root, opts
end

.load_nearest_project(path, opts = {}) ⇒ Object

Attempts to find the nearest project root



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/sproutcore/models/project.rb', line 64

def self.load_nearest_project(path, opts={})
  candidate = nil
  while path
    if Buildfile.has_buildfile?(path)
      candidate = path 
      
      # If we find a buildfile and the buildfile explicitly states 
      # that it is a project, then just stop here..
      break if Buildfile.load(path).project? 
    end
        
    new_path = File.dirname(path)
    path = (new_path == path) ? nil : new_path
  end
  (candidate) ? self.new(candidate, opts) : nil
end

Instance Method Details

#add_target(target_name, target_type, options = {}) ⇒ Object

Adds a new target to the project with the passed target name. Include the source_root for the target as well as any additional options you want copied onto the target. If a previous target was defined by the same name it will be replaced by this one.

Params

target_name:: the name of the target.
target_type:: the type of target

Options (any others allowed also)

source_root:: the absolute path to the target source

Returns

new target


183
184
185
186
# File 'lib/sproutcore/models/project.rb', line 183

def add_target(target_name, target_type, options={})
  targets[target_name] = Target.new(target_name.to_sym, 
      target_type.to_sym, options.merge(:project => self))
end

#buildfileObject

The current buildfile for the project. The buildfile is calculated by merging any parent project buildfile with the contents of any buildfiles found in the current project. Buildfiles include any file named “Buildfile”, “sc-config”, or “sc-config.rb”. You can also specify your own buildfile names with the “buildfile_names” config in the SC.env.

Returns

Buildfile instance


100
101
102
# File 'lib/sproutcore/models/project.rb', line 100

def buildfile
  @buildfile ||= (parent_project.nil? ? Buildfile.new : parent_project.buildfile.dup).load!(project_root)
end

#configObject

The config for the current project. The config is computed by merging the config settings from the current buildfile and then the current environment in the following order:

config for all modes, all targets +
config for current mode, all targets +
Current environment defined in SC.env

This is the config hash you should access to determine general project wide settings that cannot be overridden by individual targets.

Returns

merged HashStruct


118
119
120
# File 'lib/sproutcore/models/project.rb', line 118

def config
  return @config ||= buildfile.config_for(:all, SC.build_mode).merge(SC.env)
end

#find_targets_for(root_path, root_name, config) ⇒ Object

Called by project to discover any targets within the project itself.

The default implementation will search the project root directory for any directories matching those named in the “target_types” config. (See Buildfile for documentation). It will then recursively descend into each target looking for further nested targets unless you’ve set the “allow_nested_targets” config to false.

If you need to change the way the project autodiscovers its own targets you can either change the “target_types” and “allow_nested_targets” configs or you can override this method in your own ruby code to do whatever kind of changes you want.

Params

root_path:: The path to search for targets.
root_name:: The root target name
config::    The config hash to use for this.  Should come from target

Returns

self


208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/sproutcore/models/project.rb', line 208

def find_targets_for(root_path, root_name, config)
  
  # look for directories matching the target_types keys and create target
  # with target_types value as type. -- normalize to lowercase string
  target_types = {}
  (config.target_types || {}).each do |key, value| 
    target_types[key.to_s.downcase] = value
  end

  # look for directories matching a target type
  Dir.glob(File.join(root_path, '*')).each do |dir_name|
    target_type = target_types[File.basename(dir_name).to_s.downcase]
    next if target_type.nil?
    next unless File.directory?(dir_name)

    # loop through each item in the directory.  
    Dir.glob(File.join(dir_name,'*')).each do |source_root|
      next unless File.directory?(source_root)

      # compute target name and create target
      target_name = [root_name, File.basename(source_root)] * '/'
      target = self.add_target target_name, target_type,
        :source_root => source_root
      
      # if target's config allows nested targets, then call recursively
      # asking the target's config allows the target's Buildfile to 
      # override the default.
      if target.config.allow_nested_targets
        find_targets_for(source_root, target_name, target.config)
      end
    end # Dir.glob
  end # target_type.each
  return self
end

#generator_for(generator_name, opts = {}) ⇒ Object

Attempts to discover and load a generator with the specified name from the current project. If the generator cannot be found, this method will return nil.



250
251
252
253
# File 'lib/sproutcore/models/project.rb', line 250

def generator_for(generator_name, opts={})
  opts[:target_project] = self
  return SC::Generator.load(generator_name, opts)
end

#inspectObject



45
46
47
# File 'lib/sproutcore/models/project.rb', line 45

def inspect
  "SC::Project(#{File.basename(project_root || '')})"
end

#reload!Object



86
87
88
# File 'lib/sproutcore/models/project.rb', line 86

def reload!
  @buildfile = @targets = nil
end

#target_for(target_name) ⇒ Object

Returns the target with the specified target name. The target name may be absolute path or not, both will lookup from the top.

Params

target_name:: the target to lookup

Returns

a Target instance or nil if no matching target could be found


163
164
165
166
# File 'lib/sproutcore/models/project.rb', line 163

def target_for(target_name)
  ret = (targets[target_name.to_s.sub(/^([^\/])/,'/\1')])
  ret.nil? ? nil : ret
end

#targetsObject

A hash of the known targets for this project, including any targets inherited from a parent project. Each target is stored in the hash by target_name.

The first time this method is called, the project will automatically clone any targets from a parent project, and then calls find_targets_for() on itself to recursively discover any targets in the project.

If you need to change the way the project discovers project, override find_targets_for() instead of this method.

Returns

Hash of targets keyed by target_name


141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/sproutcore/models/project.rb', line 141

def targets
  return @targets unless @targets.nil?
  
  # Create an empty targets hash or clone from parent project
  @targets = HashStruct.new
  dup_targets(parent_project.targets) if parent_project

  # find targets inside project.  
  find_targets_for(project_root, nil, self.config)
  
  return @targets
end