Added solution.language; code refactoring (r397:402)

This commit is contained in:
starkos 2008-06-10 18:42:59 +00:00
parent bce9ab296c
commit 7907a92a31
22 changed files with 395 additions and 86 deletions

View File

@ -9,8 +9,8 @@
#include <sys/stat.h>
#include "premake.h"
#include "base/buffers.h"
#include "base/error.h"
#include "base/dir.h"
#include "base/error.h"
#include "base/path.h"
#include "platform/platform.h"

31
src/base/file.c Normal file
View File

@ -0,0 +1,31 @@
/**
* \file file.c
* \brief File handling.
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*/
#include <assert.h>
#include <sys/stat.h>
#include "premake.h"
#include "base.h"
/**
* Determine if a particular file exists on the filesystem.
* \returns True if the file exists.
*/
int file_exists(const char* path)
{
struct stat buf;
assert(path);
if (stat(path, &buf) == 0)
{
return ((buf.st_mode & S_IFDIR) == 0);
}
else
{
return 0;
}
}

19
src/base/file.h Normal file
View File

@ -0,0 +1,19 @@
/**
* \file file.h
* \brief File handling.
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*
* \defgroup dir File Management
* \ingroup base
*
* File management functions.
*
* @{
*/
#if !defined(PREMAKE_DIR_H)
#define PREMAKE_DIR_H
int file_exists(const char* path);
#endif
/** @} */

View File

@ -11,6 +11,7 @@
#include "action/action.h"
#include "base/cstr.h"
#include "base/error.h"
#include "base/file.h"
/** argv, as passed into main(), stored here to be accessible to all host functions. */
@ -61,6 +62,13 @@ int host_run_action(Session sess)
assert(sess);
/* there must be a project file defined or I can go no further */
if (!file_exists(DEFAULT_SCRIPT_NAME))
{
error_set("script file '%s' not found", DEFAULT_SCRIPT_NAME);
return !OKAY;
}
/* find the action in the master list and execute the associated callback */
action = Args[0];
for (i = 0; Actions[i].name != NULL; ++i)
@ -86,9 +94,17 @@ int host_run_script(Session sess)
{
assert(sess);
/* run the default file for now */
session_run_file(sess, DEFAULT_SCRIPT_NAME);
return (error_get() == NULL) ? OKAY : !OKAY;
/* run the default file for now. If the script file doesn't exist let execution
* continue so I can display help, etc. */
if (file_exists(DEFAULT_SCRIPT_NAME))
{
session_run_file(sess, DEFAULT_SCRIPT_NAME);
return (error_get() == NULL) ? OKAY : !OKAY;
}
else
{
return OKAY;
}
}

View File

@ -39,6 +39,8 @@ int main(int argc, const char** argv)
{
return host_tests();
}
#else
UNUSED(argc);
#endif
/* initialize */

View File

@ -66,6 +66,20 @@ void fields_destroy(Fields fields)
}
/**
* Add a new value to the end of an existing list.
* \param fields The collection of fields.
* \param index The index of the list to contain the new value.
* \param value The value to add.
*/
void fields_add_value(Fields fields, int index, const char* value)
{
assert(fields);
assert(index >= 0 && index < fields->count);
strings_add(fields->values[index], value);
}
/**
* Retrieve the value of a string (single value) field.
* \param fields The collection of fields.

View File

@ -48,6 +48,7 @@ DECLARE_CLASS(Fields)
Fields fields_create(struct FieldInfo* info);
void fields_destroy(Fields fields);
void fields_add_value(Fields fields, int index, const char* value);
const char* fields_get_value(Fields fields, int index);
Strings fields_get_values(Fields fields, int index);
void fields_set_value(Fields fields, int index, const char* value);

View File

@ -9,6 +9,7 @@
#include <string.h>
#include "premake.h"
#include "project/project.h"
#include "project/solution.h"
#include "base/buffers.h"
#include "base/cstr.h"
#include "base/guid.h"
@ -19,18 +20,19 @@
struct FieldInfo ProjectFieldInfo[] =
{
{ "basedir", StringField, NULL },
{ "files", FilesField, NULL },
{ "guid", StringField, guid_is_valid },
{ "language", StringField, project_is_valid_language },
{ "location", StringField, NULL },
{ "name", StringField, NULL },
{ 0, 0, NULL }
{ "basedir", StringField, NULL },
{ "files", FilesField, NULL },
{ "guid", StringField, guid_is_valid },
{ "language", StringField, NULL },
{ "location", StringField, NULL },
{ "name", StringField, NULL },
{ 0, 0, NULL }
};
DEFINE_CLASS(Project)
{
Solution solution;
Fields fields;
const char* config_filter;
};
@ -43,6 +45,7 @@ DEFINE_CLASS(Project)
Project project_create()
{
Project prj = ALLOC_CLASS(Project);
prj->solution = NULL;
prj->fields = fields_create(ProjectFieldInfo);
prj->config_filter = NULL;
return prj;
@ -86,6 +89,16 @@ const char* project_get_configuration_filter(Project prj)
}
/**
* Retrieve the fields object for this solution; used to unload values from the script.
*/
Fields project_get_fields(Project prj)
{
assert(prj);
return prj->fields;
}
/**
* Get the path to the project output file, using the provided file extension.
* \param prj The project object to query.
@ -149,7 +162,12 @@ const char* project_get_guid(Project prj)
*/
const char* project_get_language(Project prj)
{
return project_get_value(prj, ProjectLanguage);
const char* result = project_get_value(prj, ProjectLanguage);
if (result == NULL && prj->solution != NULL)
{
result = solution_get_language(prj->solution);
}
return result;
}
@ -193,6 +211,17 @@ const char* project_get_outfile(Project prj)
}
/**
* Retrieve the solution associated with this project (internal).
* \param prj The project to query.
* \returns The associated solution, or NULL if no association has been made.
*/
Solution project_get_solution(Project prj)
{
return prj->solution;
}
/**
* Retrieve a string (single value) fields from a project, using the field indices.
* \param prj The project object to query.
@ -290,6 +319,18 @@ void project_set_name(Project prj, const char* name)
}
/**
* Associate a solution with this project (internal).
* \param prj The project to modify.
* \param sln The solution to associate with this project.
*/
void project_set_solution(Project prj, Solution sln)
{
assert(prj);
prj->solution = sln;
}
/**
* Set a string (single value) field on a project, using the field indices.
* \param prj The project object.

View File

@ -40,6 +40,7 @@ void project_destroy(Project prj);
const char* project_get_base_dir(Project prj);
const char* project_get_configuration_filter(Project prj);
Fields project_get_fields(Project prj);
const char* project_get_filename(Project prj, const char* basename, const char* ext);
Strings project_get_files(Project prj);
const char* project_get_guid(Project prj);

View File

@ -0,0 +1,8 @@
/**
* \file project_internal.h
* \brief The project object's internal APIs, for communicating connectivity.
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*/
Solution project_get_solution(Project prj);
void project_set_solution(Project prj, Solution sln);

View File

@ -8,6 +8,7 @@
#include <stdlib.h>
#include "premake.h"
#include "project/solution.h"
#include "project/project_internal.h"
#include "base/array.h"
#include "base/path.h"
#include "base/strings.h"
@ -17,17 +18,18 @@
struct FieldInfo SolutionFieldInfo[] =
{
{ "basedir", StringField, NULL },
{ "location", StringField, NULL },
{ "name", StringField, NULL },
{ 0, 0, NULL }
{ "basedir", StringField, NULL },
{ "configurations", ListField, NULL },
{ "language", StringField, project_is_valid_language },
{ "location", StringField, NULL },
{ "name", StringField, NULL },
{ 0, 0, NULL }
};
DEFINE_CLASS(Solution)
{
Fields fields;
Strings configs;
Array projects;
Strings project_names;
};
@ -41,7 +43,6 @@ Solution solution_create()
{
Solution sln = ALLOC_CLASS(Solution);
sln->fields = fields_create(SolutionFieldInfo);
sln->configs = strings_create();
sln->projects = array_create();
sln->project_names = NULL;
return sln;
@ -58,7 +59,6 @@ void solution_destroy(Solution sln)
assert(sln);
fields_destroy(sln->fields);
strings_destroy(sln->configs);
n = solution_num_projects(sln);
for (i = 0; i < n; ++i)
@ -86,7 +86,7 @@ void solution_add_config_name(Solution sln, const char* config_name)
{
assert(sln);
assert(config_name);
strings_add(sln->configs, config_name);
fields_add_value(sln->fields, SolutionConfigurations, config_name);
}
@ -100,6 +100,7 @@ void solution_add_project(Solution sln, Project prj)
assert(sln);
assert(prj);
array_add(sln->projects, prj);
project_set_solution(prj, sln);
}
@ -123,9 +124,11 @@ const char* solution_get_base_dir(Solution sln)
*/
const char* solution_get_config_name(Solution sln, int index)
{
Strings names;
const char* name;
assert(sln);
name = strings_item(sln->configs, index);
names = fields_get_values(sln->fields, SolutionConfigurations);
name = strings_item(names, index);
return name;
}
@ -138,7 +141,17 @@ const char* solution_get_config_name(Solution sln, int index)
Strings solution_get_config_names(Solution sln)
{
assert(sln);
return sln->configs;
return fields_get_values(sln->fields, SolutionConfigurations);
}
/**
* Retrieve the fields object for this solution; used to unload values from the script.
*/
Fields solution_get_fields(Solution sln)
{
assert(sln);
return sln->fields;
}
@ -177,6 +190,17 @@ const char* solution_get_filename(Solution sln, const char* basename, const char
}
/**
* Get the programming language set globally for the solution.
* \param sln The solution object to modify.
* \returns The language set for the solution, or NULL if no language has been set.
*/
const char* solution_get_language(Solution sln)
{
return solution_get_value(sln, SolutionLanguage);
}
/**
* Retrieve the output location (the relative path from the base directory to the
* target output directory) for this solution.
@ -260,8 +284,10 @@ const char* solution_get_value(Solution sln, enum SolutionField field)
*/
int solution_num_configs(Solution sln)
{
Strings names;
assert(sln);
return strings_size(sln->configs);
names = fields_get_values(sln->fields, SolutionConfigurations);
return strings_size(names);
}
@ -288,6 +314,17 @@ void solution_set_base_dir(Solution sln, const char* base_dir)
}
/**
* Set the global programming language for the solution.
* \param sln The solution to modify.
* \param language The programming language to set globally for the solution.
*/
void solution_set_language(Solution sln, const char* language)
{
solution_set_value(sln, SolutionLanguage, language);
}
/*
* Set the output location (the relative path from the base directory to the
* target output directory) for this solution.

View File

@ -21,6 +21,8 @@
enum SolutionField
{
SolutionBaseDirectory,
SolutionConfigurations,
SolutionLanguage,
SolutionLocation,
SolutionName,
NumSolutionFields
@ -39,7 +41,9 @@ void solution_add_project(Solution sln, Project prj);
const char* solution_get_base_dir(Solution sln);
const char* solution_get_config_name(Solution sln, int index);
Strings solution_get_config_names(Solution sln);
Fields solution_get_fields(Solution sln);
const char* solution_get_filename(Solution sln, const char* basename, const char* ext);
const char* solution_get_language(Solution sln);
const char* solution_get_location(Solution sln);
const char* solution_get_name(Solution sln);
Project solution_get_project(Solution sln, int index);
@ -48,6 +52,7 @@ const char* solution_get_value(Solution sln, enum SolutionField field);
int solution_num_configs(Solution sln);
int solution_num_projects(Solution sln);
void solution_set_base_dir(Solution sln, const char* base_dir);
void solution_set_language(Solution sln, const char* language);
void solution_set_location(Solution sln, const char* location);
void solution_set_name(Solution sln, const char* name);
void solution_set_value(Solution sln, enum SolutionField field, const char* value);

View File

@ -7,7 +7,9 @@
#include "premake.h"
#include "testing/testing.h"
extern "C" {
#include "project/solution.h"
#include "project/project.h"
#include "project/project_internal.h"
#include "platform/platform.h"
}
@ -26,17 +28,19 @@ int project_tests()
struct FxProject
{
Solution sln;
Project prj;
FxProject()
{
sln = solution_create();
prj = project_create();
}
~FxProject()
{
if (prj)
project_destroy(prj);
project_destroy(prj);
solution_destroy(sln);
}
};
@ -138,6 +142,14 @@ SUITE(project)
CHECK_EQUAL("c++", result);
}
TEST_FIXTURE(FxProject, GetLanguage_ReturnsSolutionLanguage_OnNoProjectLanguage)
{
project_set_solution(prj, sln);
solution_set_language(sln, "c#");
const char* result = project_get_language(prj);
CHECK_EQUAL("c#", result);
}
/**********************************************************************
* Location tests
@ -199,6 +211,24 @@ SUITE(project)
const char* result = project_get_outfile(prj);
CHECK_EQUAL("MyProject.exe", result);
}
/**********************************************************************
* Solution tests
**********************************************************************/
TEST_FIXTURE(FxProject, GetSolution_ReturnsNull_OnStartup)
{
Solution result = project_get_solution(prj);
CHECK(result == NULL);
}
TEST_FIXTURE(FxProject, SetSolution_CanRoundtrip)
{
project_set_solution(prj, sln);
CHECK(sln == project_get_solution(prj));
}
}

View File

@ -9,6 +9,7 @@
extern "C" {
#include "project/solution.h"
#include "project/project.h"
#include "project/project_internal.h"
#include "base/strings.h"
}
@ -112,6 +113,24 @@ SUITE(project)
}
/**********************************************************************
* Language tests
**********************************************************************/
TEST_FIXTURE(FxSolution, GetLanguage_ReturnsNull_OnStartup)
{
const char* result = solution_get_language(sln);
CHECK(result == NULL);
}
TEST_FIXTURE(FxSolution, SetLanguage_CanRoundtrip)
{
solution_set_language(sln, "c++");
const char* result = solution_get_language(sln);
CHECK_EQUAL("c++", result);
}
/**********************************************************************
* Location tests
**********************************************************************/
@ -178,6 +197,13 @@ SUITE(project)
CHECK(prj == result);
}
TEST_FIXTURE(FxSolution, AddProject_SetsProjectSolution)
{
Project prj = project_create();
solution_add_project(sln, prj);
CHECK(sln == project_get_solution(prj));
}
TEST_FIXTURE(FxSolution, GetProjectNames_ReturnsNames)
{
Project prj = project_create();

View File

@ -10,26 +10,6 @@
SUITE(script)
{
/**************************************************************************
* Initial state tests
**************************************************************************/
TEST_FIXTURE(FxAccessor, Accessor_FunctionExists_OnStartup)
{
const char* result = script_run_string(script,
"return (location ~= nil)");
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Accessor_RaisesError_OnNoActiveObject)
{
Script script = script_create();
const char* result = script_run_string(script, "location()");
CHECK_EQUAL("no active solution or project", result);
script_destroy(script);
}
/**************************************************************************
* String field tests
**************************************************************************/
@ -120,7 +100,7 @@ SUITE(script)
/**************************************************************************
* List field tests
* Files field tests
**************************************************************************/
TEST_FIXTURE(FxAccessor, Accessor_ExpandsWildcards)

View File

@ -0,0 +1,34 @@
/**
* \file fn_configurations_tests.cpp
* \brief Automated tests for the configurations() function.
* \author Copyright (c) 2007-2008 Jason Perkins and the Premake project
*/
#include "premake.h"
#include "script_tests.h"
SUITE(script)
{
TEST_FIXTURE(FxAccessor, Configurations_Exists_OnStartup)
{
const char* result = script_run_string(script,
"return (configurations ~= nil)");
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Configurations_Error_OnNoActiveSolution)
{
Script script = script_create();
const char* result = script_run_string(script, "configurations {'Debug'}");
CHECK_EQUAL("no active solution", result);
script_destroy(script);
}
TEST_FIXTURE(FxAccessor, Configurations_CanRoundtrip)
{
const char* result = script_run_string(script,
"configurations {'Debug'};"
"return configurations()[1]");
CHECK_EQUAL("Debug", result);
}
}

View File

@ -16,4 +16,20 @@ SUITE(script)
"return (files ~= nil)");
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Files_Error_OnNoActiveProject)
{
Script script = script_create();
const char* result = script_run_string(script, "files {'hello.c'}");
CHECK_EQUAL("no active project", result);
script_destroy(script);
}
TEST_FIXTURE(FxAccessor, Files_CanRoundtrip)
{
const char* result = script_run_string(script,
"files {'hello.c'};"
"return files()[1]");
CHECK_EQUAL("hello.c", result);
}
}

View File

@ -20,6 +20,14 @@ SUITE(script)
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Guid_Error_OnNoActiveProject)
{
Script script = script_create();
const char* result = script_run_string(script, "guid()");
CHECK_EQUAL("no active project", result);
script_destroy(script);
}
TEST_FIXTURE(FxAccessor, Guid_CanRoundtrip)
{
const char* result = script_run_string(script,

View File

@ -17,6 +17,14 @@ SUITE(script)
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Guid_Error_OnNoActiveObject)
{
Script script = script_create();
const char* result = script_run_string(script, "language()");
CHECK_EQUAL("no active solution or project", result);
script_destroy(script);
}
TEST_FIXTURE(FxAccessor, Language_CanRoundtrip)
{
const char* result = script_run_string(script,

View File

@ -0,0 +1,35 @@
/**
* \file fn_location_tests.cpp
* \brief Automated tests for the location() function.
* \author Copyright (c) 2007-2008 Jason Perkins and the Premake project
*/
#include "premake.h"
#include "script_tests.h"
SUITE(script)
{
TEST_FIXTURE(FxAccessor, Location_Exists_OnStartup)
{
const char* result = script_run_string(script,
"return (location ~= nil)");
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Location_Error_OnNoActiveProject)
{
Script script = script_create();
const char* result = script_run_string(script, "location()");
CHECK_EQUAL("no active solution or project", result);
script_destroy(script);
}
TEST_FIXTURE(FxAccessor, Location_CanRoundtrip)
{
const char* result = script_run_string(script,
"location 'elsewhere';"
"return location()");
CHECK_EQUAL("elsewhere", result);
}
}

View File

@ -26,6 +26,7 @@ struct FxUnloadSolution
script_run_string(script,
"sln = solution('MySolution');"
" configurations { 'Debug', 'Release' };"
"return sln");
}
@ -52,5 +53,13 @@ SUITE(unload)
const char* result = solution_get_base_dir(sln);
CHECK_EQUAL("(string)", result);
}
TEST_FIXTURE(FxUnloadSolution, UnloadSolution_SetsConfigurations)
{
unload_solution(L, sln);
CHECK(solution_num_configs(sln) == 2);
CHECK_EQUAL("Debug", solution_get_config_name(sln, 0));
CHECK_EQUAL("Release", solution_get_config_name(sln, 1));
}
}

View File

@ -85,52 +85,16 @@ static int unload_solution_projects(lua_State* L, struct UnloadFuncs* funcs, Sol
}
/**
* Unload information from the scripting environment for a particular solution.
* \param L The Lua scripting engine state.
* \param sln The solution object to be populated.
* \returns OKAY if successful.
*/
int unload_solution(lua_State* L, Solution sln)
{
const char* value;
assert(L);
assert(sln);
lua_getfield(L, -1, "name");
value = lua_tostring(L, -1);
solution_set_name(sln, value);
lua_pop(L, 1);
lua_getfield(L, -1, "basedir");
value = lua_tostring(L, -1);
solution_set_base_dir(sln, value);
lua_pop(L, 1);
return OKAY;
}
/**
* Unload information from the scripting environment for a particular project.
* \param L The Lua scripting engine state.
* \param prj The project object to be populated.
* \returns OKAY if successful.
*/
int unload_project(lua_State* L, Project prj)
int unload_fields(lua_State* L, Fields fields, struct FieldInfo* info)
{
const char* value;
int fi;
assert(L);
assert(prj);
for (fi = 0; fi < NumProjectFields; ++fi)
for (fi = 0; info[fi].name != NULL; ++fi)
{
Strings values = strings_create();
lua_getfield(L, -1, ProjectFieldInfo[fi].name);
lua_getfield(L, -1, info[fi].name);
if (lua_istable(L, -1))
{
int i, n;
@ -159,10 +123,34 @@ int unload_project(lua_State* L, Project prj)
lua_pop(L, 1);
/* store the field values */
project_set_values(prj, fi, values);
fields_set_values(fields, fi, values);
}
return OKAY;
}
/**
* Unload information from the scripting environment for a particular solution.
* \param L The Lua scripting engine state.
* \param sln The solution object to be populated.
* \returns OKAY if successful.
*/
int unload_solution(lua_State* L, Solution sln)
{
return unload_fields(L, solution_get_fields(sln), SolutionFieldInfo);
}
/**
* Unload information from the scripting environment for a particular project.
* \param L The Lua scripting engine state.
* \param prj The project object to be populated.
* \returns OKAY if successful.
*/
int unload_project(lua_State* L, Project prj)
{
return unload_fields(L, project_get_fields(prj), ProjectFieldInfo);
}