mtbuild 0.0.9 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ce4ca21ffea4af4267971c9c01d59adfd0e7714
4
- data.tar.gz: 5d5f4ca2dca2af2fdfe2826be295bab65889782a
3
+ metadata.gz: 2396c6643e11dac5f4237283b8008a2197a6f836
4
+ data.tar.gz: 633bd1821dcaa7e207456763c2b57b648a380078
5
5
  SHA512:
6
- metadata.gz: 1d2da1d95635f92f69e733d8cd370191d592b88305ed608a7bbc4e74bb531a8872dc474b142f46d579a1034971e565b9379bf072cd3a0da964ba708527f4ddb9
7
- data.tar.gz: ab6032db4a20132d3656d1a57c3c334a4038cb9fef1862447ea300145ee91c0aef315bfa3a38f9f9ad45d95a0aee6134ba5b3e7e563672bb0376497126903ddd
6
+ metadata.gz: ebf955f1536eaa5cb307ef35ae5494aceaeb7352c25f43920a23797cc03acbceac0121c0a8179d059f9c79fead2b4a340133936b994ecb436f9740bcef16f6b3
7
+ data.tar.gz: 1d9c4e05c3ea9ff8ba8ba60bbc2a64e3cf9186a579e72ca5ecc5b308d0c3330e0855ee336931f420ac360ed6e6c82c0f231043bf850c033eb0c9057f5e4e664d
data/CHANGES.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Release Notes #
2
2
 
3
+
4
+ ## MTBuild 0.1.0 ##
5
+
6
+ ### Changes ###
7
+
8
+ * MTBuild v0.1.0 is a big, API-breaking change.
9
+ * MTBuild now requires Ruby >= 2.0.0.
10
+ * MTBuild now overrides the rake application name to display "mtbuild" as the
11
+ application name.
12
+ * MTBuild now offers a '--super-dry-run' command line option to perform a dry
13
+ run of the build where each command is printed, but not executed.
14
+ * Workspaces can now include other workspaces to inherit their projects and
15
+ configurations.
16
+ * Default tasks can no longer be added to projects. You can only add default
17
+ tasks to workspaces. If you need default tasks for a project, simply include
18
+ a lightweight workspace that exists solely to specify default tasks.
19
+ * The "clobber" task is now gone. MTbuild workspaces now generate a top-level
20
+ "clean" task that cleans all projects. Additionally, each project provides
21
+ its own "clean" task for cleaning just one project at a time. The "clean"
22
+ tasks remove all intermediate files and final output, so they behave like
23
+ the older Rake "clobber" task.
24
+ * Added the "gpp" toolchains. These are similar to the gcc toolchains, but they
25
+ invoke g++ instead of gcc.
26
+
27
+
3
28
  ## MTBuild 0.0.9 ##
4
29
 
5
30
  ### Changes ###
@@ -8,6 +33,7 @@
8
33
  * Fixed bug that prevented library include path specification for gcc-based
9
34
  toolchains.
10
35
 
36
+
11
37
  ## MTBuild 0.0.8 ##
12
38
 
13
39
  ### Changes ###
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014, Mindtribe Product Engineering, Inc.
1
+ Copyright (c) 2014-2015, Mindtribe Product Engineering, Inc.
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
data/README.md CHANGED
@@ -45,8 +45,6 @@ application_project :MyApp, File.dirname(__FILE__) do |app|
45
45
  linker_script: 'src/LinkerFile-Debug.ld'
46
46
  )
47
47
 
48
- app.add_default_tasks('MyApp:Debug')
49
-
50
48
  end
51
49
  ```
52
50
 
@@ -70,7 +68,7 @@ The ARM toolchain should use the specified linker flags when linking (```ldflags
70
68
 
71
69
  The ARM toolchain should use the specified linker script when linking (```linker_script: ...```)
72
70
 
73
- When invoked with no parameters, MTBuild will build the Debug configuration of MyApp by default (```app.add_default_tasks('MyApp:Debug')```)
71
+ When invoked with no parameters, MTBuild will do nothing for this project. When invoked as ```mtbuild 'MyApp:Debug'```, MTBuild will build the ```Debug``` configuration of ```MyApp```.
74
72
 
75
73
  You can find more project examples here: [MTBuild examples](https://github.com/Mindtribe/MTBuild/tree/master/examples)
76
74
 
@@ -135,6 +133,12 @@ MTBuild uses Rake. MTBuild projects and workspaces are defined using mtbuildfile
135
133
 
136
134
  Building is as simple as invoking ```mtbuild``` in a folder containing a mtbuildfile. Under the hood, MTBuild pulls in the MTBuild infrastructure and then invokes Rake.
137
135
 
136
+ ##### Command Line Options #####
137
+
138
+ MTBuild supports the standard Rake command line options. Additionally, it adds the following:
139
+
140
+ * ```--super-dry-run``` This command performs a dry run; however, unlike the Rake dry run, it actually prints the shell commands that would be executed.
141
+
138
142
  #### Project Hierarchy ####
139
143
 
140
144
  The MTBuild project hierarchy looks roughly like this:
@@ -179,13 +183,13 @@ An MTBuild workspace contains MTBuild projects and can provide default settings
179
183
 
180
184
  MTBuild workspaces are optional. It's possible to build an MTBuild project by itself--assuming the project provides all settings required to build & isn't relying on a workspace to provide those.
181
185
 
182
- MTBuild builds only the first workspace it finds. If a workspace includes a project that provides its own workspace, the project's workspace is ignored and the higher-level workspace is used. This allows projects--such as libraries--to be built by themselves or included in other workspaces while allowing the workspace to define toolchain settings.
186
+ MTBuild allows workspaces to be nested. A workspace can include another workspace, allowing the parent to reference the child workspace's projects. When you include a child workspace from within your workspace, you can choose whether or not to pull in the child's default tasks. You can also choose to pull configurations up from the child or push configurations down to the child.
183
187
 
184
188
  ###### Simple Workspace Example #####
185
189
 
186
- mtbuildfile.rb:
190
+ This defines a workspace that includes the "MyLibrary" and "MyApp" projects. The projects are presumed to be defined in their own mtbuildfiles inside sub-folders called "MyLibrary" and "MyApp".
187
191
 
188
- This defines a workspace that includes the "MyLibrary" and "MyApp" projects. The projects are presumed to be defined in their own mtbuildfiles inside sub-folders called "MyLibrary" and "MyApp":
192
+ mtbuildfile.rb:
189
193
 
190
194
  ```Ruby
191
195
  workspace :AppWithLibrary, File.dirname(__FILE__) do |w|
@@ -196,9 +200,9 @@ end
196
200
 
197
201
  ###### Project Plus Workspace Example #####
198
202
 
199
- mtbuildfile.rb:
203
+ This defines a workspace that includes the MyLibrary project, which is defined in the same mtbuildfile. When a project is defined in the same mtbuildfile, it does not need to be explicitly added to the workspace (in this particular example, the workspace isn't very useful).
200
204
 
201
- This defines a workspace that includes the MyLibrary project, which is defined in the same mtbuildfile. When a project is defined in the same mtbuildfile, it does not need to be explicitly added to the workspace (in this particular example, the workspace isn't very useful):
205
+ mtbuildfile.rb:
202
206
 
203
207
  ```Ruby
204
208
  workspace :MyWorkspace, File.dirname(__FILE__) do |w|
@@ -216,9 +220,9 @@ end
216
220
 
217
221
  ###### Project Plus Workspace With Defaults Example #####
218
222
 
219
- mtbuildfile.rb:
223
+ This defines a workspace that includes the MyLibrary project, which is defined in the same mtbuildfile. The workspace provides a default toolchain for the "Debug" configuration. A higher-level workspace would override this with its own defaults.
220
224
 
221
- This defines a workspace that includes the MyLibrary project, which is defined in the same mtbuildfile. The workspace provides a default toolchain for the "Debug" configuration. A higher-level workspace would override this with its own defaults:
225
+ mtbuildfile.rb:
222
226
 
223
227
  ```Ruby
224
228
  workspace :MyLibrary, File.dirname(__FILE__) do |w|
@@ -235,6 +239,19 @@ static_library_project :MyLibrary, File.dirname(__FILE__) do |lib|
235
239
  end
236
240
  ```
237
241
 
242
+ ###### Nested Workspace Example #####
243
+
244
+ This defines a workspace that includes a "MyLibrary" workspace and pulls up a configuration called "Debug" from the "MyLibrary" workspace. This makes the library's "Debug" configuration settings available to the "MyApp" project, allowing "MyApp" to be built with the same toolchain settings as "MyLibrary".
245
+
246
+ mtbuildfile.rb:
247
+
248
+ ```Ruby
249
+ workspace :AppWithLibrary, File.dirname(__FILE__) do |w|
250
+ w.add_workspace('MyLibrary', pull_configurations: [:Debug])
251
+ w.add_project('MyApp')
252
+ end
253
+ ```
254
+
238
255
  #### Dependencies ####
239
256
 
240
257
  Configurations can list dependencies that will be built before the configuration. A configuration's dependencies are specified as a list of Rake tasks. Therefore, these dependencies can refer to other MTBuild projects or any Rake task.
@@ -350,8 +367,23 @@ For ```configuration_block```, you supply a block that takes one parameter. When
350
367
  #### add_project ####
351
368
  Use ```add_project(project_location)``` inside of a workspace configuration block to add a project that lives inside a subfolder. The ```project_location``` parameter must be a subfolder of the workspace. If the project lives at the same level as the workspace, you should define it in the same mtbuildfile as the workspace. In this case, the project will be implicitly added and you do not need to use ```add_project``` inside the workspace. See the **Project Plus Workspace Example** above for an example of a workspace and project that live at the same folder level.
352
369
 
370
+ #### add_workspace ####
371
+ Use ```add_workspace(workspace_location, pull_default_tasks: false, pull_configurations: [], push_configurations: [])``` inside of a workspace configuration block to add a child workspace that lives inside a subfolder. The ```workspace_location``` parameter must be a subfolder of the workspace.
372
+
373
+ The optional, named parameter, ```pull_default_tasks``` determines whether the parent workspace should pull in the child workspace's default tasks. If this is ```true```, then when ```mtbuild``` is run on the parent workspace with no specified build targets, the child workspace's default targets will be built. If this is ```false```, then only targets that are referenced from the child workspace will be built as needed.
374
+
375
+ The optional, named parameter ```pull_configurations``` specifies a list of configurations to pull up from the child workspace. Pulling up configurations makes them available to other projects included by the parent workspace.
376
+
377
+ The optional, named parameter ```push_configurations``` specifies a list of configurations to push down to the child workspace. Pushing down configurations allows you to add to a child workspace's configuration settings. Note that pushing a configuration down to a child cannot be used to create a new configuration for that child. It only lets you add configuration settings to child configurations that already exist. MTBuild ignores pushed configurations that do not exist in the child workspace's projects. Pushing down a configuration is intended to allow a parent workspace to override or add to a child's build settings. This should be used rarely and with caution since it's generally assumed that projects in a child workspace have been tested with the settings provided by that workspace.
378
+
353
379
  #### add_default_tasks ####
354
- Use ```add_default_tasks(default_tasks)``` inside of a workspace configuration block to add tasks that run when you invoke MTBuild with no arguments. The ```default_tasks``` parameter expects one or more (in an array) Rake tasks. If no default tasks are specified, then invoking MTBuild with no arguments will effectively do nothing.
380
+ Use ```add_default_tasks(default_tasks)``` inside of a workspace configuration block to add tasks that run when you invoke MTBuild with no arguments. The ```default_tasks``` parameter expects one or more (in an array) project task names. The project tasks should be qualified relative to the current workspace. For example, if a workspace includes a project called ```MyApp```, which has a configuration called ```Debug```, you can add this by referring to it as ```MyApp:Debug```. If no default tasks are specified, then invoking MTBuild with no arguments will effectively do nothing.
381
+
382
+ #### add_default_rake_tasks ####
383
+ Use ```add_default_rake_tasks(default_tasks)``` inside of a workspace configuration block to add tasks that run when you invoke MTBuild with no arguments. The ```default_tasks``` parameter expects one or more (in an array) Rake task names. Unlike ```add_default_tasks()```, this method expects "raw" Rake task names. This lets you specify that MTBuild should run any Rake task by default when building this workspace.
384
+
385
+ #### MTBuild::Workspace.add_default_tasks ####
386
+ Use the class method ```MTBuild::Workspace.add_default_tasks(default_tasks)``` to add a default task outside of a workspace configuration block. This is useful for letting projects register default tasks in the project's mtbuildfile.rb. Note that the tasks specified in the ```default_tasks``` list must be fully-qualified ```mtbuild``` names that take workspace nesting into account. You should use the project method ```task_for_configuration``` to get the correct task names.
355
387
 
356
388
  #### set_configuration_defaults ####
357
389
  Use ```set_configuration_defaults(configuration_name, defaults_hash)``` inside of a workspace configuration block to add default settings for a configuration. This is how you would select, for instance, a default toolchain for all projects with a specific configuration.
@@ -395,6 +427,13 @@ end
395
427
  #### set_output_folder ####
396
428
  Use ```set_output_folder(output_folder)``` inside of a workspace configuration block to change the build output folder. By default, this folder is set to "build" underneath the workspace folder. The ```output_folder``` parameter expects the name of a folder relative to the workspace. If the folder does not exist, MTBuild will create it.
397
429
 
430
+ ### MTBuild::Project ###
431
+
432
+ This is a base class for projects. You won't typically use it directly, but it provides some useful methods for all project types.
433
+
434
+ #### task_for_configuration ####
435
+ Use ```task_for_configuration(config_name)``` to get the fully qualified task name for the project configuration called ```config_name```. This is useful for getting fully qualified task names to register as default tasks using ```MTBuild::Workspace.add_default_tasks```
436
+
398
437
 
399
438
  ### MTBuild::ApplicationProject ###
400
439
 
@@ -536,8 +575,9 @@ All toolchains offer the following optional settings:
536
575
 
537
576
  * ```:library_paths``` - One or more library paths to search when linking. For example, ```'FancyLibrary/lib'``` or ```['FancyLibrary/lib', 'SuperFancyLibrary/lib']```. Note that the paths should be relative to the project folder.
538
577
 
578
+
539
579
  ### MTBuild::ToolchainGcc ###
540
- Define a GCC toolchain by passing ```:gcc``` as the ```toolchain_name``` when invoking the ```toolchain()``` method.
580
+ Define a gcc toolchain by passing ```:gcc``` as the ```toolchain_name``` when invoking the ```toolchain()``` method.
541
581
 
542
582
  ##### ToolchainGcc settings #####
543
583
  On top of the base Toolchain settings, the ToolchainGcc toolchain offers the following optional settings:
@@ -554,14 +594,28 @@ On top of the base Toolchain settings, the ToolchainGcc toolchain offers the fol
554
594
 
555
595
  * ```:linker_script``` - A linker script file to be used when linking
556
596
 
597
+
598
+ ### MTBuild::ToolchainGpp ###
599
+ Define a g++ toolchain by passing ```:gpp``` as the ```toolchain_name``` when invoking the ```toolchain()``` method.
600
+
601
+ ##### ToolchainGpp settings #####
602
+ The ToolchainGpp toolchain uses the same settings as the ToolchainGcc toolchain.
603
+
604
+
557
605
  ### MTBuild::ToolchainArmNoneEabiGcc ###
558
606
  Define an arm-none-eabi-gcc toolchain by passing ```:arm_none_eabi_gcc``` as the ```toolchain_name``` when invoking the ```toolchain()``` method.
559
607
 
560
608
  ##### ToolchainArmNoneEabiGcc settings #####
561
609
  The ToolchainArmNoneEabiGcc toolchain uses the same settings as the ToolchainGcc toolchain.
562
610
 
563
- ### MTBuild::Versioner ###
611
+ ### MTBuild::ToolchainArmNoneEabiGpp ###
612
+ Define an arm-none-eabi-g++ toolchain by passing ```:arm_none_eabi_gpp``` as the ```toolchain_name``` when invoking the ```toolchain()``` method.
613
+
614
+ ##### ToolchainArmNoneEabiGpp settings #####
615
+ The ToolchainArmNoneEabiGpp toolchain uses the same settings as the ToolchainGcc toolchain.
564
616
 
617
+
618
+ ### MTBuild::Versioner ###
565
619
  Define a Versioner with the following DSL method:
566
620
 
567
621
  ```Ruby
data/bin/mtbuild CHANGED
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ lib_path_expanded = File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
4
+ if File.directory?(lib_path_expanded)
5
+ $:.unshift(lib_path_expanded) unless $:.include?(lib_path_expanded)
6
+ end
7
+
3
8
  require 'mtbuild'
4
9
 
5
10
  Rake.application.run
data/lib/mtbuild.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module MTBuild
2
2
  # The current MTBuild version.
3
- VERSION = '0.0.9'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
 
6
6
  require 'rake'
@@ -9,8 +9,6 @@ end
9
9
 
10
10
  module MTBuild
11
11
 
12
- require 'rake'
13
-
14
12
  # This subclasses the Rake::Application class to override default Rake
15
13
  # behaviors with MTBuild-specific behaviors
16
14
  class Application < Rake::Application
@@ -32,6 +30,19 @@ module MTBuild
32
30
  @rakefiles = DEFAULT_RAKEFILES.dup
33
31
  end
34
32
 
33
+ def run
34
+ standard_exception_handling do
35
+ init
36
+ load_rakefile
37
+ top_level
38
+ end
39
+ end
40
+
41
+ # Override init to pass mtbuild as the app name
42
+ def init(app_name='mtbuild')
43
+ super
44
+ end
45
+
35
46
  # This modifies Rake's command line options to do MTBuild-specific things
36
47
  def standard_rake_options
37
48
  # This hijacks the "--version" flag and displays the MTBuild version along
@@ -50,10 +61,17 @@ module MTBuild
50
61
  opt
51
62
  end
52
63
  end
53
- # This adds MTBuild-specific options (For future development)
54
- # options |= [
55
- # ]
56
- # sort_options(options)
64
+ # This adds MTBuild-specific options
65
+ options |= [
66
+ ['--super-dry-run',
67
+ "Do a dry run printing actions, but not executing them.",
68
+ lambda { |value|
69
+ Rake.verbose(true)
70
+ Rake.nowrite(true)
71
+ }
72
+ ],
73
+ ]
74
+ sort_options(options)
57
75
  end
58
76
 
59
77
  end
@@ -18,10 +18,10 @@ module MTBuild
18
18
  all_object_folders |= object_folders
19
19
  end
20
20
 
21
- application_binaries, application_files, application_folders = @default_toolchain.create_application_tasks(all_object_files, @project_name)
21
+ application_binaries, application_files, application_folders = @default_toolchain.create_application_tasks(all_object_files, @parent_project.project_name)
22
22
  dependencies = @dependencies+all_object_folders+application_folders+application_files+application_binaries
23
23
 
24
- desc "Build application '#{@project_name}' with configuration '#{@configuration_name}'"
24
+ desc "Build application '#{@parent_project.project_name}' with configuration '#{@configuration_name}'"
25
25
  new_task = application_task @configuration_name => dependencies do |t|
26
26
  puts "built application #{t.name}."
27
27
  @tests.each do |test|
@@ -34,12 +34,12 @@ module MTBuild
34
34
  end
35
35
 
36
36
  namespace @configuration_name do
37
- OrganizedPackageTask.new("#{@project_name}-#{@configuration_name}", :noversion) do |t|
37
+ OrganizedPackageTask.new("#{@parent_project.project_name}-#{@configuration_name}", :noversion) do |t|
38
38
  t.need_tar_gz = true
39
39
  t.add_files_to_folder("", application_binaries+application_files)
40
40
  end
41
41
  end
42
- Rake::Task[:"#{@project_name}:#{@configuration_name}:package"].prerequisites.insert(0, :"#{@project_name}:#{@configuration_name}")
42
+ Rake::Task[:"#{@parent_project.project_name}:#{@configuration_name}:package"].prerequisites.insert(0, :"#{@parent_project.project_name}:#{@configuration_name}")
43
43
 
44
44
  end
45
45
 
@@ -9,11 +9,12 @@ module MTBuild
9
9
  # Adds a named ApplicationConfiguration to the project.
10
10
  def add_configuration(configuration_name, configuration)
11
11
  super
12
- default_configuration = Workspace.configuration_defaults.fetch(configuration_name, {})
12
+ default_configuration = {}
13
+ default_configuration = @parent_workspace.configuration_defaults.fetch(configuration_name, {}) unless @parent_workspace.nil?
13
14
  merged_configuration = Utils.merge_configurations(default_configuration, configuration)
14
- cfg = ApplicationConfiguration.new(@project_name, @project_folder, effective_output_folder, configuration_name, merged_configuration)
15
+ cfg = ApplicationConfiguration.new(self, effective_output_folder, configuration_name, merged_configuration)
15
16
  @configurations << cfg
16
- return cfg
17
+ cfg
17
18
  end
18
19
 
19
20
  end
@@ -0,0 +1,104 @@
1
+ module MTBuild
2
+
3
+ # This class holds the mtbuild workspace hierarchy
4
+ class BuildRegistry
5
+
6
+ @workspaces = {}
7
+ @projects = {}
8
+ @top_workspace = nil
9
+ @active_workspace = nil
10
+
11
+ @expecting=:project_or_workspace
12
+
13
+ class << self
14
+
15
+ # The map of registered workspaces
16
+ attr_reader :workspaces
17
+
18
+ # The map of registered projects
19
+ attr_reader :projects
20
+
21
+ # The top-level workspace
22
+ attr_reader :top_workspace
23
+
24
+ # The top-level workspace
25
+ attr_reader :active_workspace
26
+
27
+ # Track the beginning of a new workspace's creation
28
+ def enter_workspace(workspace_name, workspace)
29
+ workspace_name = self.hierarchical_name(workspace_name)
30
+ self.found_workspace(workspace_name)
31
+ fail "A workspace named #{workspace_name} was already added." if @workspaces.has_key?(workspace_name)
32
+ @workspaces[workspace_name] = workspace
33
+ @top_workspace = workspace if @top_workspace.nil?
34
+ parent = @active_workspace
35
+ @active_workspace = workspace
36
+ return workspace_name, parent
37
+ end
38
+
39
+ # Track the re-entry into a parent workspace after importing a child workspace.
40
+ def reenter_workspace(workspace)
41
+ last_workspace = @active_workspace
42
+ @active_workspace = workspace
43
+ last_workspace
44
+ end
45
+
46
+ # Track the completion of a new workspace's creation
47
+ def exit_workspace
48
+ end
49
+
50
+ # Track the beginning of a new project's creation
51
+ def enter_project(project_name, project)
52
+ project_name = self.hierarchical_name(project_name)
53
+ self.found_project(project_name)
54
+ fail "A project named #{project_name} was already added." if @projects.has_key?(project_name)
55
+ @projects[project_name] = project
56
+ return project_name, @active_workspace
57
+ end
58
+
59
+ # Track the completion of a new project's creation
60
+ def exit_project
61
+ end
62
+
63
+ # Register that we next expect to encounter a workspace, not a project
64
+ def expect_workspace
65
+ # We expect an explicitly-added workspace.
66
+ @expecting=:added_workspace
67
+ end
68
+
69
+ # Register that we next expect to encounter a project, not a workspace
70
+ def expect_project
71
+ # We expect an explicitly-added project.
72
+ @expecting=:added_project
73
+ end
74
+
75
+ # Register that we encountered a workspace and verify that it's allowed
76
+ def found_workspace(workspace_name)
77
+ unless [:project_or_workspace, :added_workspace].include? @expecting
78
+ fail "#{workspace_name} was added with add_project(), but it contains a workspace. Use add_workspace() if you want to include it." if @expecting==:added_project
79
+ fail "Encountered workspace #{workspace_name} declared after a project or another workspace in the same file. This isn't allowed."
80
+ end
81
+ # We expect nothing but top-level projects now.
82
+ @expecting=:project
83
+ end
84
+
85
+ # Register that we encountered a project and verify that it's allowed
86
+ def found_project(project_name)
87
+ unless [:project_or_workspace, :project, :added_project].include? @expecting
88
+ fail "#{project_name} was added with add_workspace(), but it contains a project. Use add_project() if you want to include it." if @expecting==:added_workspace
89
+ end
90
+ # We expect nothing but top-level projects now.
91
+ @expecting=:project
92
+ end
93
+
94
+ # Get a workspace/project name that reflects the workspace/project hierarchy
95
+ def hierarchical_name(name)
96
+ return name if @active_workspace.nil?
97
+ "#{@active_workspace.workspace_name}:#{name}"
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+
104
+ end