From 95c23ec10b46be79d16c807a83e33b2f0a846a4a Mon Sep 17 00:00:00 2001 From: starkos Date: Wed, 13 Aug 2008 15:25:06 +0000 Subject: [PATCH] Completed implementation of location function and project-relative pathing (r479:485) --- src/actions/make/make.c | 45 ++++++------- src/actions/make/make_solution.c | 8 ++- .../make/tests/make_solution_tests.cpp | 6 +- src/actions/make/tests/make_tests.cpp | 14 ++--- src/actions/tests/action_tests.h | 3 +- .../vs200x/tests/vs2002_solution_tests.cpp | 2 +- src/actions/vs200x/vs2002_solution.c | 10 +-- src/base/path.c | 1 - src/base/strings.c | 29 +++++++-- src/objects/block.c | 4 +- src/objects/block.h | 2 +- src/objects/fields.c | 29 ++++++++- src/objects/fields.h | 25 ++++---- src/objects/project.c | 54 ++++++++-------- src/objects/project.h | 5 +- src/objects/solution.c | 27 ++------ src/objects/solution.h | 4 +- src/objects/tests/project_tests.cpp | 32 ++++------ src/objects/tests/solution_tests.cpp | 22 ------- src/script/fn_accessor.c | 26 ++++---- src/script/fn_configurations.c | 4 +- src/script/fn_project.c | 2 +- src/script/fn_solution.c | 2 +- src/script/script_internal.c | 9 +-- src/script/script_internal.h | 6 +- src/script/tests/unload_project_tests.cpp | 30 ++++++++- src/script/tests/unload_solution_tests.cpp | 11 +++- src/script/unload.c | 63 ++++++++++++++++++- 28 files changed, 287 insertions(+), 188 deletions(-) diff --git a/src/actions/make/make.c b/src/actions/make/make.c index 4fd3e0c6..b55b90e7 100644 --- a/src/actions/make/make.c +++ b/src/actions/make/make.c @@ -63,46 +63,49 @@ 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 */ - my_path = project_get_filename(prj, NULL, ".make"); - return my_path; + in_conflict = 1; } } } } + /* if a conflict was detected use an alternate name */ + if (in_conflict) + { + my_path = project_get_filename(prj, NULL, ".make"); + } + /* all good */ return my_path; } @@ -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 */ diff --git a/src/actions/make/make_solution.c b/src/actions/make/make_solution.c index ab99d3a3..1f8d0564 100644 --- a/src/actions/make/make_solution.c +++ b/src/actions/make/make_solution.c @@ -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)) { diff --git a/src/actions/make/tests/make_solution_tests.cpp b/src/actions/make/tests/make_solution_tests.cpp index 28f0655b..a6169f85 100644 --- a/src/actions/make/tests/make_solution_tests.cpp +++ b/src/actions/make/tests/make_solution_tests.cpp @@ -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" diff --git a/src/actions/make/tests/make_tests.cpp b/src/actions/make/tests/make_tests.cpp index 9f2c9a9a..d02947a6 100644 --- a/src/actions/make/tests/make_tests.cpp +++ b/src/actions/make/tests/make_tests.cpp @@ -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); } diff --git a/src/actions/tests/action_tests.h b/src/actions/tests/action_tests.h index 97d49ad3..39127b89 100644 --- a/src/actions/tests/action_tests.h +++ b/src/actions/tests/action_tests.h @@ -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"); diff --git a/src/actions/vs200x/tests/vs2002_solution_tests.cpp b/src/actions/vs200x/tests/vs2002_solution_tests.cpp index c42db2aa..2042fa7a 100644 --- a/src/actions/vs200x/tests/vs2002_solution_tests.cpp +++ b/src/actions/vs200x/tests/vs2002_solution_tests.cpp @@ -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); } diff --git a/src/actions/vs200x/vs2002_solution.c b/src/actions/vs200x/vs2002_solution.c index 5e01b229..2338fc48 100644 --- a/src/actions/vs200x/vs2002_solution.c +++ b/src/actions/vs200x/vs2002_solution.c @@ -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"); } diff --git a/src/base/path.c b/src/base/path.c index 1648aa71..001b5002 100644 --- a/src/base/path.c +++ b/src/base/path.c @@ -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) { diff --git a/src/base/strings.c b/src/base/strings.c index 70a7a95e..504d6ce4 100644 --- a/src/base/strings.c +++ b/src/base/strings.c @@ -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); } diff --git a/src/objects/block.c b/src/objects/block.c index db73d057..335802f5 100644 --- a/src/objects/block.c +++ b/src/objects/block.c @@ -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 } }; diff --git a/src/objects/block.h b/src/objects/block.h index 9ba9b03a..2962ff94 100644 --- a/src/objects/block.h +++ b/src/objects/block.h @@ -25,7 +25,7 @@ enum BlockField NumBlockFields }; -extern struct FieldInfo BlockFieldInfo[]; +extern FieldInfo BlockFieldInfo[]; DECLARE_CLASS(Block) diff --git a/src/objects/fields.c b/src/objects/fields.c index fe27f1b5..cff8c4bc 100644 --- a/src/objects/fields.c +++ b/src/objects/fields.c @@ -13,8 +13,9 @@ DEFINE_CLASS(Fields) { - Strings* values; - int count; + 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; +} diff --git a/src/objects/fields.h b/src/objects/fields.h index c4401c7b..206b9416 100644 --- a/src/objects/fields.h +++ b/src/objects/fields.h @@ -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. */ - FieldValidator validator; /**< The field validation function */ -}; + const char* name; /**< The name of the field. */ + 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 /* @} */ diff --git a/src/objects/project.c b/src/objects/project.c index 643ca298..7813f552 100644 --- a/src/objects/project.c +++ b/src/objects/project.c @@ -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,33 +190,38 @@ 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); } - - - if (!ext) - { - ext = ""; - } - - 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; + return path_assemble(location, basename, 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) +{ + 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); +} + + + /** * Retrieve the list of source files associated with a project. */ @@ -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); } diff --git a/src/objects/project.h b/src/objects/project.h index ec41a5ce..4e4b9bbe 100644 --- a/src/objects/project.h +++ b/src/objects/project.h @@ -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); diff --git a/src/objects/solution.c b/src/objects/solution.c index 05f003b4..d02e1c81 100644 --- a/src/objects/solution.c +++ b/src/objects/solution.c @@ -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); } diff --git a/src/objects/solution.h b/src/objects/solution.h index 90e72ab1..59224e16 100644 --- a/src/objects/solution.h +++ b/src/objects/solution.h @@ -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); diff --git a/src/objects/tests/project_tests.cpp b/src/objects/tests/project_tests.cpp index ad2a2d70..8bb57d1c 100644 --- a/src/objects/tests/project_tests.cpp +++ b/src/objects/tests/project_tests.cpp @@ -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)); } diff --git a/src/objects/tests/solution_tests.cpp b/src/objects/tests/solution_tests.cpp index aba736bb..ccf20737 100644 --- a/src/objects/tests/solution_tests.cpp +++ b/src/objects/tests/solution_tests.cpp @@ -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 **********************************************************************/ diff --git a/src/script/fn_accessor.c b/src/script/fn_accessor.c index 68e2db86..c8b6a976 100644 --- a/src/script/fn_accessor.c +++ b/src/script/fn_accessor.c @@ -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; diff --git a/src/script/fn_configurations.c b/src/script/fn_configurations.c index 95747749..96615b8a 100644 --- a/src/script/fn_configurations.c +++ b/src/script/fn_configurations.c @@ -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) diff --git a/src/script/fn_project.c b/src/script/fn_project.c index acb7aaef..48746344 100644 --- a/src/script/fn_project.c +++ b/src/script/fn_project.c @@ -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()); diff --git a/src/script/fn_solution.c b/src/script/fn_solution.c index c4cd93f7..ba3e8521 100644 --- a/src/script/fn_solution.c +++ b/src/script/fn_solution.c @@ -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); diff --git a/src/script/script_internal.c b/src/script/script_internal.c index b5acaa55..fe57d520 100644 --- a/src/script/script_internal.c +++ b/src/script/script_internal.c @@ -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); diff --git a/src/script/script_internal.h b/src/script/script_internal.h index f64e5dfd..8836eb04 100644 --- a/src/script/script_internal.h +++ b/src/script/script_internal.h @@ -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); diff --git a/src/script/tests/unload_project_tests.cpp b/src/script/tests/unload_project_tests.cpp index 1bc88330..efb60af1 100644 --- a/src/script/tests/unload_project_tests.cpp +++ b/src/script/tests/unload_project_tests.cpp @@ -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); + } } diff --git a/src/script/tests/unload_solution_tests.cpp b/src/script/tests/unload_solution_tests.cpp index 8aad7f5b..eef5668b 100644 --- a/src/script/tests/unload_solution_tests.cpp +++ b/src/script/tests/unload_solution_tests.cpp @@ -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); + } } diff --git a/src/script/unload.c b/src/script/unload.c index 70e4f248..32fe1728 100644 --- a/src/script/unload.c +++ b/src/script/unload.c @@ -7,10 +7,12 @@ #include #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; +}