Completed implementation of location function and project-relative pathing (r479:485)

This commit is contained in:
starkos 2008-08-13 15:25:06 +00:00
parent bcc678cb91
commit 95c23ec10b
28 changed files with 287 additions and 188 deletions

View File

@ -63,44 +63,47 @@ const char* make_get_obj_filename(const char* filename)
const char* make_get_project_makefile(Project prj)
{
const char* my_path;
const char* their_path;
int si, sn;
int si, sn, in_conflict = 0;
Session sess = project_get_session(prj);
/* get the full makefile path for this project */
my_path = project_get_filename(prj, "Makefile", NULL);
/* get the default filename for this project */
my_path = project_get_filename(prj, "Makefile", "");
/* see if any other solution wants to use this same path */
sn = session_num_solutions(sess);
for (si = 0; si < sn; ++si)
for (si = 0; si < sn && !in_conflict; ++si)
{
const char* their_path;
int pi, pn;
Solution sln2 = session_get_solution(sess, si);
their_path = solution_get_filename(sln2, "Makefile", NULL);
Solution sln = session_get_solution(sess, si);
their_path = solution_get_filename(sln, "Makefile", "");
if (cstr_eq(my_path, their_path))
{
/* conflict; use the alternate name */
my_path = project_get_filename(prj, NULL, ".make");
return my_path;
in_conflict = 1;
}
/* check any projects contained by this solution */
pn = solution_num_projects(sln2);
for (pi = 0; pi < pn; ++pi)
pn = solution_num_projects(sln);
for (pi = 0; pi < pn && !in_conflict; ++pi)
{
Project prj2 = solution_get_project(sln2, pi);
Project prj2 = solution_get_project(sln, pi);
if (prj != prj2)
{
their_path = project_get_filename(prj2, "Makefile", NULL);
their_path = project_get_filename(prj2, "Makefile", "");
if (cstr_eq(my_path, their_path))
{
/* conflict; use the alternate name */
in_conflict = 1;
}
}
}
}
/* if a conflict was detected use an alternate name */
if (in_conflict)
{
my_path = project_get_filename(prj, NULL, ".make");
return my_path;
}
}
}
}
/* all good */
@ -142,12 +145,12 @@ Strings make_get_project_names(Solution sln)
const char* make_get_solution_makefile(Solution sln)
{
const char* my_path;
const char* their_path;
int i, n;
Session sess = solution_get_session(sln);
/* get the full makefile path for this solution */
my_path = solution_get_filename(sln, "Makefile", NULL);
/* get the default file name for this solution */
my_path = solution_get_filename(sln, "Makefile", "");
/* see if any other solution wants to use this same path */
n = session_num_solutions(sess);
@ -156,7 +159,7 @@ const char* make_get_solution_makefile(Solution sln)
Solution them = session_get_solution(sess, i);
if (them != sln)
{
their_path = solution_get_filename(them, "Makefile", NULL);
const char* their_path = solution_get_filename(them, "Makefile", "");
if (cstr_eq(my_path, their_path))
{
/* conflict; use the alternate name */

View File

@ -111,13 +111,15 @@ const char* make_solution_project_rule(Solution sln, Project prj)
char* buffer = buffers_next();
/* project file paths are specified relative to the solution */
const char* sln_path = path_directory(solution_get_filename(sln, NULL, NULL));
const char* sln_file_dir = solution_get_location(sln);
const char* prj_file = make_get_project_makefile(prj);
const char* prj_file_dir = path_directory(prj_file);
const char* prj_file_name = path_filename(prj_file);
prj_file_dir = path_relative(sln_path, prj_file_dir);
prj_file_dir = path_relative(sln_file_dir, prj_file_dir);
/* build the rule */
strcpy(buffer, "\t@$(MAKE)");
if (!cstr_eq(".", prj_file_dir))
{

View File

@ -83,7 +83,7 @@ SUITE(action)
TEST_FIXTURE(FxAction, Make_ProjectEntry_InSameDirectory)
{
project_set_location(prj, "");
project_set_location(prj, solution_get_location(sln));
make_solution_projects(sln, strm);
CHECK_EQUAL(
"My\\ Project:\n"
@ -95,7 +95,7 @@ SUITE(action)
TEST_FIXTURE(FxAction, Make_ProjectEntry_InDifferentDirectory)
{
project_set_location(prj, "My Project");
project_set_location(prj, "Root Folder/Solution Folder/My Project");
make_solution_projects(sln, strm);
CHECK_EQUAL(
"My\\ Project:\n"
@ -112,7 +112,7 @@ SUITE(action)
TEST_FIXTURE(FxAction, Gmake_CleanRule_IsCorrect)
{
project_set_location(prj, "");
project_set_location(prj, solution_get_location(sln));
make_solution_clean_rule(sln, strm);
CHECK_EQUAL(
"clean:\n"

View File

@ -40,7 +40,7 @@ struct FxMake
Solution sln = solution_create();
session_add_solution(sess, sln);
solution_set_name(sln, name);
solution_set_base_dir(sln, ".");
solution_set_location(sln, ".");
return sln;
}
@ -49,7 +49,7 @@ struct FxMake
Project prj = project_create();
solution_add_project(sln1, prj);
project_set_name(prj, name);
project_set_base_dir(prj, ".");
project_set_location(prj, ".");
return prj;
}
};
@ -63,7 +63,7 @@ SUITE(action)
TEST_FIXTURE(FxMake, GetSolutionMakefile_ReturnsMakefile_OnUniqueLocation)
{
solution_set_location(sln1, "MySolution");
solution_set_location(sln1, "./MySolution");
const char* result = make_get_solution_makefile(sln1);
CHECK_EQUAL("./MySolution/Makefile", result);
}
@ -76,22 +76,22 @@ SUITE(action)
TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsMakefile_OnUniqueLocation)
{
project_set_location(prj1, "MyProject");
project_set_location(prj1, "./MyProject");
const char* result = make_get_project_makefile(prj1);
CHECK_EQUAL("./MyProject/Makefile", result);
}
TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsDotMake_OnSharedWithSolution)
{
project_set_location(prj2, "MyProject");
project_set_location(prj2, "./MyProject");
const char* result = make_get_project_makefile(prj1);
CHECK_EQUAL("./MyProject1.make", result);
}
TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsDotMake_OnSharedWithProject)
{
project_set_location(prj1, "MyProject");
project_set_location(prj2, "MyProject");
project_set_location(prj1, "./MyProject");
project_set_location(prj2, "./MyProject");
const char* result = make_get_project_makefile(prj1);
CHECK_EQUAL("./MyProject/MyProject1.make", result);
}

View File

@ -29,6 +29,7 @@ struct FxAction
session_add_solution(sess, sln);
solution_set_name(sln, "My Solution");
solution_set_base_dir(sln, "Root Folder");
solution_set_location(sln, "Root Folder/Solution Folder");
solution_add_config(sln, "Debug DLL");
solution_add_config(sln, "Release DLL");
@ -36,7 +37,7 @@ struct FxAction
solution_add_project(sln, prj);
project_set_name(prj, "My Project");
project_set_base_dir(prj, "Root Folder");
project_set_location(prj, "Project Folder");
project_set_location(prj, "Root Folder/Project Folder");
project_set_guid(prj, "AE2461B7-236F-4278-81D3-F0D476F9A4C0");
project_set_language(prj, "c++");
project_set_config(prj, "Debug DLL");

View File

@ -34,7 +34,7 @@ SUITE(action)
{
vs2002_solution_projects(sln, strm);
CHECK_EQUAL(
"Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"My Project\", \"Project Folder\\My Project.vcproj\", \"{AE2461B7-236F-4278-81D3-F0D476F9A4C0}\"\n"
"Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"My Project\", \"..\\Project Folder\\My Project.vcproj\", \"{AE2461B7-236F-4278-81D3-F0D476F9A4C0}\"\n"
"EndProject\n",
buffer);
}

View File

@ -96,12 +96,7 @@ int vs2002_solution_project_configuration(Solution sln, Stream strm)
*/
int vs2002_solution_projects(Solution sln, Stream strm)
{
const char* sln_path;
int i, n, z = OKAY;
/* project file paths are specified relative to the solution */
sln_path = path_directory(solution_get_filename(sln, NULL, NULL));
n = solution_num_projects(sln);
for (i = 0; i < n; ++i)
{
@ -110,13 +105,10 @@ int vs2002_solution_projects(Solution sln, Stream strm)
const char* prj_id = project_get_guid(prj);
const char* prj_lang = project_get_language(prj);
const char* prj_ext = vs200x_project_file_extension(prj);
const char* prj_file = project_get_filename(prj, prj_name, prj_ext);
const char* prj_file = project_get_filename_relative(prj, prj_name, prj_ext);
const char* tool_id = vs200x_tool_guid(prj_lang);
/* convert absolute project file name to be relative to solution */
prj_file = path_relative(sln_path, prj_file);
prj_file = path_translate(prj_file, "\\");
z |= stream_writeline(strm, "Project(\"{%s}\") = \"%s\", \"%s\", \"{%s}\"", tool_id, prj_name, prj_file, prj_id);
z |= stream_writeline(strm, "EndProject");
}

View File

@ -236,7 +236,6 @@ char* path_join(const char* leading, const char* trailing)
/* treat nulls like empty paths */
leading = (leading != NULL) ? leading : "";
trailing = (trailing != NULL) ? trailing : "";
if (!trailing)
{

View File

@ -8,6 +8,8 @@
#include "premake.h"
#include "strings.h"
#include "base/array.h"
#include "base/string.h"
DEFINE_CLASS(Strings)
{
@ -50,6 +52,13 @@ Strings strings_create_from_array(const char* items[])
*/
void strings_destroy(Strings strs)
{
int i, n;
n = strings_size(strs);
for (i = 0; i < n; ++i)
{
String item = (String)array_item(strs->contents, i);
string_destroy(item);
}
array_destroy(strs->contents);
free(strs);
}
@ -62,7 +71,8 @@ void strings_destroy(Strings strs)
*/
void strings_add(Strings strs, const char* item)
{
array_add(strs->contents, (void*)item);
String str = string_create(item);
array_add(strs->contents, (void*)str);
}
@ -73,7 +83,13 @@ void strings_add(Strings strs, const char* item)
*/
void strings_append(Strings dest, Strings src)
{
array_append(dest->contents, src->contents);
int i, n;
n = strings_size(src);
for (i = 0; i < n; ++i)
{
const char* item = strings_item(src, i);
strings_add(dest, item);
}
}
@ -85,7 +101,8 @@ void strings_append(Strings dest, Strings src)
*/
const char* strings_item(Strings strs, int index)
{
return (const char*)array_item(strs->contents, index);
String item = (String)array_item(strs->contents, index);
return string_cstr(item);
}
@ -97,7 +114,11 @@ const char* strings_item(Strings strs, int index)
*/
void strings_set(Strings strs, int index, const char* item)
{
array_set(strs->contents, index, (void*)item);
String str = (String)array_item(strs->contents, index);
string_destroy(str);
str = string_create(item);
array_set(strs->contents, index, (void*)str);
}

View File

@ -12,10 +12,10 @@
#include "base/env.h"
struct FieldInfo BlockFieldInfo[] =
FieldInfo BlockFieldInfo[] =
{
{ "defines", ListField, NULL },
{ "objdir", StringField, NULL },
{ "objdir", PathField, NULL },
{ "terms", ListField, NULL },
{ 0, 0, NULL }
};

View File

@ -25,7 +25,7 @@ enum BlockField
NumBlockFields
};
extern struct FieldInfo BlockFieldInfo[];
extern FieldInfo BlockFieldInfo[];
DECLARE_CLASS(Block)

View File

@ -13,6 +13,7 @@
DEFINE_CLASS(Fields)
{
FieldInfo* info;
Strings* values;
int count;
};
@ -23,7 +24,7 @@ DEFINE_CLASS(Fields)
* \param info Metadata about the field collection.
* \returns A new collection of fields.
*/
Fields fields_create(struct FieldInfo* info)
Fields fields_create(FieldInfo* info)
{
int i;
Fields fields;
@ -31,6 +32,7 @@ Fields fields_create(struct FieldInfo* info)
assert(info);
fields = ALLOC_CLASS(Fields);
fields->info = info;
/* figure out how many fields are in the collection */
for (i = 0; info[i].name != NULL; ++i);
@ -76,6 +78,17 @@ void fields_add_value(Fields fields, int index, const char* value)
}
/**
* Identify the type of field at the given index.
*/
FieldKind fields_get_kind(Fields fields, int index)
{
assert(fields);
assert(index >= 0 && index < fields->count);
return fields->info[index].kind;
}
/**
* Retrieve the value of a string (single value) field.
* \returns The field value if set, or NULL.
@ -149,3 +162,13 @@ void fields_set_values(Fields fields, int index, Strings values)
fields->values[index] = values;
}
/**
* Return the number of fields in the collection.
*/
int fields_size(Fields fields)
{
assert(fields);
return fields->count;
}

View File

@ -20,12 +20,13 @@
/**
* Field types.
*/
enum FieldKind
typedef enum enum_FieldKind
{
StringField,
ListField,
FilesField
};
StringField, /**< field containing a single, string value */
ListField, /**< field containing a list of string values */
FilesField, /**< field containing a list of file names */
PathField /**< field containing a file path (directory or file name) */
} FieldKind;
/**
@ -39,25 +40,27 @@ typedef int (*FieldValidator)(const char* value);
/**
* Metadata about a project object field.
*/
struct FieldInfo
typedef struct struct_FieldInfo
{
const char* name; /**< The name of the field. */
enum FieldKind kind; /**< StringField, ListField, etc. */
FieldKind kind; /**< StringField, ListField, etc. */
FieldValidator validator; /**< The field validation function */
};
} FieldInfo;
DECLARE_CLASS(Fields)
Fields fields_create(struct FieldInfo* info);
Fields fields_create(FieldInfo* info);
void fields_destroy(Fields fields);
void fields_add_value(Fields fields, int index, const char* value);
FieldKind fields_get_kind(Fields fields, int index);
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);
void fields_set_values(Fields fields, int index, Strings values);
int fields_size(Fields fields);
#endif
/* @} */

View File

@ -17,7 +17,7 @@
#include "base/strings.h"
struct FieldInfo ProjectFieldInfo[] =
FieldInfo ProjectFieldInfo[] =
{
{ "basedir", StringField, NULL },
{ "files", FilesField, NULL },
@ -87,7 +87,7 @@ void project_destroy(Project prj)
*/
const char* project_get_base_dir(Project prj)
{
return project_get_value(prj, ProjectBaseDirectory);
return project_get_value(prj, ProjectBaseDir);
}
@ -157,7 +157,6 @@ Strings project_get_config_values(Project prj, enum BlockField field)
project_get_values_from_blocks(prj, values, solution_get_blocks(prj->solution), field);
project_get_values_from_blocks(prj, values, project_get_blocks(prj), field);
return values;
}
@ -183,7 +182,7 @@ Fields project_get_fields(Project prj)
/**
* Get the path to the project output file, using the provided file extension.
* Get the path to the project output file, using the provided file name and extension.
* \param prj The project object to query.
* \param basename The base filename; if NULL the project name will be used.
* \param ext The file extension to be used on the filename; may be NULL.
@ -191,31 +190,36 @@ Fields project_get_fields(Project prj)
*/
const char* project_get_filename(Project prj, const char* basename, const char* ext)
{
const char* base_dir;
const char* location;
const char* directory;
const char* result;
assert(prj);
const char* location = project_get_location(prj);
if (!basename)
{
basename = project_get_name(prj);
}
return path_assemble(location, basename, ext);
}
if (!ext)
/**
* Get the relative path from the solution to the project file, using the
* provided file name and extension.
* \param prj The project object to query.
* \param basename The base filename; if NULL the project name will be used.
* \param ext The file extension to be used on the filename; may be NULL.
* \returns The path to the project file.
*/
const char* project_get_filename_relative(Project prj, const char* basename, const char* ext)
{
ext = "";
const char* sln_location;
const char* abs_filename;
assert(prj);
assert(prj->solution);
sln_location = solution_get_location(prj->solution);
abs_filename = project_get_filename(prj, basename, ext);
return path_relative(sln_location, abs_filename);
}
base_dir = project_get_base_dir(prj);
location = project_get_location(prj);
directory = path_join(base_dir, location);
result = path_assemble(directory, basename, ext);
return result;
}
/**
@ -334,7 +338,7 @@ int project_is_valid_language(const char* language)
*/
void project_set_base_dir(Project prj, const char* base_dir)
{
project_set_value(prj, ProjectBaseDirectory, base_dir);
project_set_value(prj, ProjectBaseDir, base_dir);
}

View File

@ -24,7 +24,7 @@ DECLARE_CLASS(Project)
*/
enum ProjectField
{
ProjectBaseDirectory,
ProjectBaseDir,
ProjectFiles,
ProjectGuid,
ProjectLanguage,
@ -33,7 +33,7 @@ enum ProjectField
NumProjectFields
};
extern struct FieldInfo ProjectFieldInfo[];
extern FieldInfo ProjectFieldInfo[];
Project project_create(void);
@ -45,6 +45,7 @@ const char* project_get_config(Project prj);
Strings project_get_config_values(Project prj, enum BlockField field);
Fields project_get_fields(Project prj);
const char* project_get_filename(Project prj, const char* basename, const char* ext);
const char* project_get_filename_relative(Project prj, const char* basename, const char* ext);
Strings project_get_files(Project prj);
const char* project_get_guid(Project prj);
const char* project_get_language(Project prj);

View File

@ -15,7 +15,7 @@
#include "base/strings.h"
struct FieldInfo SolutionFieldInfo[] =
FieldInfo SolutionFieldInfo[] =
{
{ "basedir", StringField, NULL },
{ "configurations", ListField, NULL },
@ -101,7 +101,7 @@ void solution_add_project(Solution sln, Project prj)
*/
const char* solution_get_base_dir(Solution sln)
{
return solution_get_value(sln, SolutionBaseDirectory);
return solution_get_value(sln, SolutionBaseDir);
}
@ -158,29 +158,12 @@ Fields solution_get_fields(Solution sln)
*/
const char* solution_get_filename(Solution sln, const char* basename, const char* ext)
{
const char* base_dir;
const char* location;
const char* directory;
const char* result;
assert(sln);
const char* location = solution_get_location(sln);
if (!basename)
{
basename = solution_get_name(sln);
}
if (!ext)
{
ext = "";
}
base_dir = solution_get_base_dir(sln);
location = solution_get_location(sln);
directory = path_join(base_dir, location);
result = path_assemble(directory, basename, ext);
return result;
return path_assemble(location, basename, ext);
}
@ -273,7 +256,7 @@ int solution_num_projects(Solution sln)
*/
void solution_set_base_dir(Solution sln, const char* base_dir)
{
solution_set_value(sln, SolutionBaseDirectory, base_dir);
solution_set_value(sln, SolutionBaseDir, base_dir);
}

View File

@ -25,7 +25,7 @@ DECLARE_CLASS(Solution)
*/
enum SolutionField
{
SolutionBaseDirectory,
SolutionBaseDir,
SolutionConfigurations,
SolutionLanguage,
SolutionLocation,
@ -33,7 +33,7 @@ enum SolutionField
NumSolutionFields
};
extern struct FieldInfo SolutionFieldInfo[];
extern FieldInfo SolutionFieldInfo[];
Solution solution_create(void);

View File

@ -21,12 +21,16 @@ struct FxProject
FxProject()
{
sln = solution_create();
solution_set_name(sln, "MySolution");
solution_set_location(sln, "/BaseDir/MySolution");
prj = project_create();
solution_add_project(sln, prj);
project_set_name(prj, "MyProject");
}
~FxProject()
{
project_destroy(prj);
solution_destroy(sln);
}
};
@ -44,21 +48,18 @@ SUITE(project)
* Filename tests
**********************************************************************/
TEST_FIXTURE(FxProject, GetFilename_ReturnsFullPath_OnNoLocation)
TEST_FIXTURE(FxProject, GetFilenameRel_ReturnsCorrectPath_OnSameDir)
{
project_set_name(prj, "MyProject");
project_set_base_dir(prj, "/BaseDir");
const char* filename = project_get_filename(prj, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/MyProject.xyz", filename);
project_set_location(prj, "/BaseDir/MySolution");
const char* filename = project_get_filename_relative(prj, NULL, ".xyz");
CHECK_EQUAL("MyProject.xyz", filename);
}
TEST_FIXTURE(FxProject, GetFilename_ReturnsFullPath_OnLocation)
TEST_FIXTURE(FxProject, GetFilenameRel_ReturnsCorrectPath_OnDifferentDir)
{
project_set_name(prj, "MyProject");
project_set_base_dir(prj, "/BaseDir");
project_set_location(prj, "Location");
const char* filename = project_get_filename(prj, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/Location/MyProject.xyz", filename);
project_set_location(prj, "/BaseDir/MyProject");
const char* filename = project_get_filename_relative(prj, NULL, ".xyz");
CHECK_EQUAL("../MyProject/MyProject.xyz", filename);
}
@ -101,15 +102,8 @@ SUITE(project)
* 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

@ -75,28 +75,6 @@ SUITE(project)
}
/**********************************************************************
* Filename tests
**********************************************************************/
TEST_FIXTURE(FxSolution, GetFilename_ReturnsFullPath_OnNoLocation)
{
solution_set_name(sln, "MySolution");
solution_set_base_dir(sln, "/BaseDir");
const char* filename = solution_get_filename(sln, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/MySolution.xyz", filename);
}
TEST_FIXTURE(FxSolution, GetFilename_ReturnsFullPath_OnLocation)
{
solution_set_name(sln, "MySolution");
solution_set_base_dir(sln, "/BaseDir");
solution_set_location(sln, "Location");
const char* filename = solution_get_filename(sln, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/Location/MySolution.xyz", filename);
}
/**********************************************************************
* Project containment tests
**********************************************************************/

View File

@ -10,10 +10,10 @@
#include "base/error.h"
static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* field_name);
static int fn_accessor_register(lua_State* L, struct FieldInfo* fields);
static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field);
static void fn_accessor_append_value(lua_State* L, struct FieldInfo* field, int tbl, int idx);
static int fn_accessor_object_has_field(FieldInfo* fields, const char* field_name);
static int fn_accessor_register(lua_State* L, FieldInfo* fields);
static int fn_accessor_register_field(lua_State* L, FieldInfo* field);
static void fn_accessor_append_value(lua_State* L, FieldInfo* field, int tbl, int idx);
/**
@ -37,7 +37,7 @@ int fn_accessor_register_all(lua_State* L)
* Register the accessor functions for a particular set of fields.
* \returns OKAY if successful.
*/
static int fn_accessor_register(lua_State* L, struct FieldInfo* fields)
static int fn_accessor_register(lua_State* L, FieldInfo* fields)
{
int i, z = OKAY;
@ -54,7 +54,7 @@ static int fn_accessor_register(lua_State* L, struct FieldInfo* fields)
* Register a single accessor function.
* \returns OKAY if successful.
*/
static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field)
static int fn_accessor_register_field(lua_State* L, FieldInfo* field)
{
int container_type, z;
@ -84,7 +84,7 @@ static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field)
* Determine if a field list contains a field with a particular name.
* \returns True if the field is contained by the list.
*/
static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* field_name)
static int fn_accessor_object_has_field(FieldInfo* fields, const char* field_name)
{
int i;
for (i = 0; fields[i].name != NULL; ++i)
@ -104,7 +104,7 @@ static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* fi
*/
int fn_accessor(lua_State* L)
{
struct FieldInfo* field;
FieldInfo* field;
int container_type;
/* get the required container object */
@ -115,12 +115,12 @@ int fn_accessor(lua_State* L)
}
/* get information about the field being accessed */
field = (struct FieldInfo*)lua_touserdata(L, lua_upvalueindex(2));
field = (FieldInfo*)lua_touserdata(L, lua_upvalueindex(2));
/* if a value is provided, set the field */
if (lua_gettop(L) > 1)
{
if (field->kind == StringField)
if (field->kind == StringField || field->kind == PathField)
{
fn_accessor_set_string_value(L, field);
}
@ -140,7 +140,7 @@ int fn_accessor(lua_State* L)
* Sets a string field to the value on the bottom of the Lua stack.
* \returns OKAY if successful.
*/
int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field)
int fn_accessor_set_string_value(lua_State* L, FieldInfo* field)
{
/* can't set lists to simple fields */
if (lua_istable(L, 1))
@ -171,7 +171,7 @@ int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field)
* Appends the value or list at the bottom of the Lua stack to the specified list field.
* \returns OKAY if successful.
*/
int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field)
int fn_accessor_set_list_value(lua_State* L, FieldInfo* field)
{
/* get the current value of the field */
lua_getfield(L, -1, field->name);
@ -194,7 +194,7 @@ int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field)
* \param tbl The table to contain the values.
* \param idx The value to add to the table.
*/
static void fn_accessor_append_value(lua_State* L, struct FieldInfo* field, int tbl, int idx)
static void fn_accessor_append_value(lua_State* L, FieldInfo* field, int tbl, int idx)
{
int i, n;

View File

@ -13,7 +13,7 @@
*/
int fn_configurations(lua_State* L)
{
struct FieldInfo* field;
FieldInfo* field;
if (!script_internal_get_active_object(L, SolutionObject, IS_REQUIRED))
{
@ -29,7 +29,7 @@ int fn_configurations(lua_State* L)
lua_pop(L, 1);
/* get information about the field being accessed */
field = (struct FieldInfo*)lua_touserdata(L, lua_upvalueindex(2));
field = (FieldInfo*)lua_touserdata(L, lua_upvalueindex(2));
/* if a value is provided, set the field */
if (lua_gettop(L) > 1)

View File

@ -56,7 +56,7 @@ int fn_project(lua_State* L)
/* set the base directory */
lua_pushstring(L, script_internal_script_dir(L));
lua_setfield(L, -2, ProjectFieldInfo[ProjectBaseDirectory].name);
lua_setfield(L, -2, ProjectFieldInfo[ProjectBaseDir].name);
/* set a default GUID */
lua_pushstring(L, guid_create());

View File

@ -38,7 +38,7 @@ int fn_solution(lua_State* L)
/* set the base directory */
lua_pushstring(L, script_internal_script_dir(L));
lua_setfield(L, -2, SolutionFieldInfo[SolutionBaseDirectory].name);
lua_setfield(L, -2, SolutionFieldInfo[SolutionBaseDir].name);
/* create an empty list of projects */
lua_newtable(L);

View File

@ -29,7 +29,8 @@ int script_internal_create_block(lua_State* L)
/* set all list-type configuration block values to empty tables */
for (i = 0; i < NumBlockFields; ++i)
{
if (BlockFieldInfo[i].kind != StringField)
int kind = BlockFieldInfo[i].kind;
if (kind != StringField && kind != PathField)
{
lua_newtable(L);
lua_setfield(L, -2, BlockFieldInfo[i].name);
@ -184,14 +185,14 @@ const char* script_internal_script_dir(lua_State* L)
* \param L The Lua state.
* \param fields The list of object fields.
*/
void script_internal_populate_object(lua_State* L, struct FieldInfo* fields)
void script_internal_populate_object(lua_State* L, FieldInfo* fields)
{
struct FieldInfo* field;
FieldInfo* field;
/* set all list-type configuration values to empty tables */
for (field = fields; field->name != NULL; ++field)
{
if (field->kind != StringField)
if (field->kind != StringField && field->kind != PathField)
{
lua_newtable(L);
lua_setfield(L, -2, field->name);

View File

@ -40,12 +40,12 @@ int script_internal_create_block(lua_State* L);
int script_internal_get_active_object(lua_State* L, enum ObjectType type, int is_required);
void script_internal_set_active_object(lua_State* L, enum ObjectType type);
const char* script_internal_script_dir(lua_State* L);
void script_internal_populate_object(lua_State* L, struct FieldInfo* fields);
void script_internal_populate_object(lua_State* L, FieldInfo* fields);
/* Generic project object field getter/setter API */
int fn_accessor_register_all(lua_State* L);
int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field);
int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field);
int fn_accessor_set_string_value(lua_State* L, FieldInfo* field);
int fn_accessor_set_list_value(lua_State* L, FieldInfo* field);
/* script function handlers */
int fn_accessor(lua_State* L);

View File

@ -28,6 +28,7 @@ struct FxUnloadProject
"solution('MySolution');"
" configurations {'Debug','Release'};"
"prj = project('MyProject');"
" prj.basedir = '/basedir';"
" guid '0C202E43-B9AF-4972-822B-5A42F0BF008C';"
" language 'c++';"
" files { 'Hello.cpp', 'Goodbye.cpp' };"
@ -55,7 +56,7 @@ SUITE(unload)
{
unload_project(L, prj);
const char* result = project_get_base_dir(prj);
CHECK_EQUAL("(string)", result);
CHECK_EQUAL("/basedir", result);
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_UnloadsFiles)
@ -69,6 +70,18 @@ SUITE(unload)
}
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_RepointsFiles_OnLocation)
{
script_run_string(script, "location 'build'; return prj");
unload_project(L, prj);
Strings files = project_get_files(prj);
CHECK(strings_size(files) == 2);
if (strings_size(files) == 2) {
CHECK_EQUAL("../Hello.cpp", strings_item(files, 0));
CHECK_EQUAL("../Goodbye.cpp", strings_item(files, 1));
}
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsGuid)
{
unload_project(L, prj);
@ -82,5 +95,20 @@ SUITE(unload)
const char* result = project_get_language(prj);
CHECK_EQUAL("c++", result);
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsLocation_OnUnsetLocation)
{
unload_project(L, prj);
const char* result = project_get_location(prj);
CHECK_EQUAL("/basedir", result);
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsLocation_OnSetLocation)
{
script_run_string(script, "location 'location'; return prj");
unload_project(L, prj);
const char* result = project_get_location(prj);
CHECK_EQUAL("/basedir/location", result);
}
}

View File

@ -27,6 +27,8 @@ struct FxUnloadSolution
script_run_string(script,
"sln = solution('MySolution');"
" configurations { 'Debug', 'Release' };"
" sln.basedir = '/basedir';"
" location 'location';"
"return sln");
}
@ -51,7 +53,7 @@ SUITE(unload)
{
unload_solution(L, sln);
const char* result = solution_get_base_dir(sln);
CHECK_EQUAL("(string)", result);
CHECK_EQUAL("/basedir", result);
}
TEST_FIXTURE(FxUnloadSolution, UnloadSolution_SetsConfigurations)
@ -61,5 +63,12 @@ SUITE(unload)
CHECK_EQUAL("Debug", solution_get_config(sln, 0));
CHECK_EQUAL("Release", solution_get_config(sln, 1));
}
TEST_FIXTURE(FxUnloadSolution, UnloadSolution_SetsLocation)
{
unload_solution(L, sln);
const char* result = solution_get_location(sln);
CHECK_EQUAL("/basedir/location", result);
}
}

View File

@ -7,10 +7,12 @@
#include <assert.h>
#include "premake.h"
#include "script/script_internal.h"
#include "base/path.h"
static int unload_blocks(lua_State* L, struct UnloadFuncs* funcs, Blocks blocks);
static int unload_projects(lua_State* L, struct UnloadFuncs* funcs, Solution sln);
static int unload_repoint_paths(Fields fields, int base_dir_idx, int location_idx);
/**
@ -126,7 +128,7 @@ static int unload_blocks(lua_State* L, struct UnloadFuncs* funcs, Blocks blocks)
}
int unload_fields(lua_State* L, Fields fields, struct FieldInfo* info)
int unload_fields(lua_State* L, Fields fields, FieldInfo* info)
{
const char* value;
int fi;
@ -179,7 +181,10 @@ int unload_fields(lua_State* L, Fields fields, struct FieldInfo* info)
*/
int unload_solution(lua_State* L, Solution sln)
{
return unload_fields(L, solution_get_fields(sln), SolutionFieldInfo);
Fields fields = solution_get_fields(sln);
int z = unload_fields(L, fields, SolutionFieldInfo);
unload_repoint_paths(fields, SolutionBaseDir, SolutionLocation);
return z;
}
@ -191,7 +196,10 @@ int unload_solution(lua_State* L, Solution sln)
*/
int unload_project(lua_State* L, Project prj)
{
return unload_fields(L, project_get_fields(prj), ProjectFieldInfo);
Fields fields = project_get_fields(prj);
int z = unload_fields(L, fields, ProjectFieldInfo);
unload_repoint_paths(fields, ProjectBaseDir, ProjectLocation);
return z;
}
@ -205,3 +213,52 @@ int unload_block(lua_State* L, Block blk)
{
return unload_fields(L, block_get_fields(blk), BlockFieldInfo);
}
/**
* Walks a list of fields and repoints all paths to be relative to
* base_directory/location. Once this is done, all paths will end up
* relative to the generated project or solution file.
* \param fields The list of fields to repoint.
* \param base_dir_idx The index of the BaseDir field in the field list.
* \param location_idx The index of the Location field in the field list.
*/
int unload_repoint_paths(Fields fields, int base_dir_idx, int location_idx)
{
const char* base_dir;
const char* location;
int fi, fn;
/* first I have to update the Location field; this is the absolute path that
* I will base all the other relative paths upon */
base_dir = fields_get_value(fields, base_dir_idx);
location = path_join(base_dir, fields_get_value(fields, location_idx));
fields_set_value(fields, location_idx, location);
/* now I can can for other pathed fields and repoint them */
fn = fields_size(fields);
for (fi = 0; fi < fn; ++fi)
{
/* only repoint pathed fields */
int kind = fields_get_kind(fields, fi);
if (kind == FilesField || kind == PathField)
{
/* enumerate all values of the field */
int vi, vn;
Strings values = fields_get_values(fields, fi);
vn = strings_size(values);
for (vi = 0; vi < vn; ++vi)
{
const char* value = strings_item(values, vi);
const char* abs_path = path_join(base_dir, value);
const char* rel_path = path_relative(location, abs_path);
strings_set(values, vi, rel_path);
}
}
}
return OKAY;
}