aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-06-05 14:28:40 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-06 07:39:32 +0200
commit31afceeade6dd852a8b7a71805b21a20e502229a (patch)
tree54c08d6f3970802260e08f37de24fe40cae201e0 /src/main.cpp
parent0c287d0bbf28618cfe65807f7c858d19136e5854 (diff)
Add sibs init to init project in existing directory
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp260
1 files changed, 224 insertions, 36 deletions
diff --git a/src/main.cpp b/src/main.cpp
index a3f09a8..aabf83e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -90,8 +90,10 @@ using namespace std::chrono;
// TODO: Add program command for generating compile_commands.json without compiling code, without using Ninja
#if OS_FAMILY == OS_FAMILY_POSIX
+#define fout std::cout
#define ferr std::cerr
#else
+#define fout std::wcout
#define ferr std::wcerr
#endif
@@ -111,7 +113,7 @@ void usageBuild()
printf("Usage: sibs build [project_path] [--debug|--release] [--sanitize]\n\n");
printf("Build a sibs project\n\n");
printf("Options:\n");
- printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current working directory)\n");
+ printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current directory)\n");
printf(" --debug|--release\t\tOptimization level to build project and dependencies with (if not a system package) - Optional (default: --debug)\n");
printf(" --sanitize\t\tAdd runtime address/undefined behavior sanitization. Program can be up to 3 times slower and use 10 times as much RAM. Ignored if compiler doesn't support sanitization - Optional (default: disabled)\n");
printf("Examples:\n");
@@ -142,7 +144,7 @@ void usageTest()
printf("Usage: sibs test [project_path] [--no-sanitize]\n\n");
printf("Build and run tests for a sibs project\n\n");
printf("Options:\n");
- printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current working directory)\n");
+ printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current directory)\n");
printf(" --no-sanitize\t\tDisable runtime address/undefined behavior - Optional\n");
printf("Examples:\n");
printf(" sibs test\n");
@@ -150,6 +152,21 @@ void usageTest()
exit(1);
}
+void usageInit()
+{
+ printf("Usage: sibs init [project_path] <--exec|--static|--dynamic>\n\n");
+ printf("Create sibs project structure in an existing directory\n\n");
+ printf("Options:\n");
+ printf(" project_path\t\tThe directory where you want to initialize sibs project - Optional (default: current directory)\n");
+ printf(" --exec\t\t\tProject compiles to an executable\n");
+ printf(" --static\t\t\tProject compiles to a static library\n");
+ printf(" --dynamic\t\t\tProject compiles to a dynamic library\n");
+ printf("Examples:\n");
+ printf(" sibs init --exec\n");
+ printf(" sibs init dirA/dirB --dynamic");
+ exit(1);
+}
+
void validateDirectoryPath(const _tinydir_char_t *projectPath)
{
FileType projectPathFileType = getFileType(projectPath);
@@ -369,7 +386,7 @@ int buildProject(int argc, const _tinydir_char_t **argv)
int testProject(int argc, const _tinydir_char_t **argv)
{
- if(argc > 1)
+ if(argc > 2)
usageTest();
FileString projectPath;
@@ -431,37 +448,18 @@ int testProject(int argc, const _tinydir_char_t **argv)
return buildProject(projectPath, projectConfFilePath, sibsConfig);
}
-void newProjectCreateMainDir(const FileString &projectPath)
+// Returns nullptr if @charToFind is not found
+const _tinydir_char_t* findLastOf(const _tinydir_char_t *str, const int strSize, const char charToFind)
{
- Result<bool> createProjectDirResult = createDirectoryRecursive(projectPath.c_str());
- if(createProjectDirResult.isErr())
+ for(int i = strSize; i >= 0; --i)
{
- ferr << "Failed to create project main directory: " << toFileString(createProjectDirResult.getErrMsg()) << endl;
- exit(20);
+ if(str[i] == charToFind)
+ return str + i;
}
+ return nullptr;
}
-void createProjectSubDir(const FileString &dir)
-{
- Result<bool> createProjectDirResult = createDirectoryRecursive(dir.c_str());
- if(createProjectDirResult.isErr())
- {
- ferr << "Failed to create directory in project: " << toFileString(createProjectDirResult.getErrMsg()) << endl;
- exit(20);
- }
-}
-
-void createProjectFile(const FileString &projectFilePath, const string &fileContent)
-{
- Result<bool> fileOverwriteResult = fileOverwrite(projectFilePath.c_str(), fileContent.c_str());
- if(fileOverwriteResult.isErr())
- {
- ferr << "Failed to create project file: " << toFileString(fileOverwriteResult.getErrMsg()) << endl;
- exit(20);
- }
-}
-
-void newProjectCreateConf(const string &projectName, const string &projectType, const FileString &projectPath)
+Result<bool> newProjectCreateConf(const string &projectName, const string &projectType, const FileString &projectPath)
{
string projectConfStr = "[package]\n";
projectConfStr += "name = \"" + projectName + "\"\n";
@@ -476,10 +474,20 @@ void newProjectCreateConf(const string &projectName, const string &projectType,
FileString projectConfPath = projectPath;
projectConfPath += TINYDIR_STRING("/project.conf");
- Result<bool> fileOverwriteResult = fileOverwrite(projectConfPath.c_str(), projectConfStr.c_str());
+ return fileWrite(projectConfPath.c_str(), projectConfStr.c_str());
+}
+
+Result<bool> createDirectoryRecursive(const FileString &dir)
+{
+ return createDirectoryRecursive(dir.c_str());
+}
+
+void createProjectFile(const FileString &projectFilePath, const string &fileContent)
+{
+ Result<bool> fileOverwriteResult = fileOverwrite(projectFilePath.c_str(), fileContent.c_str());
if(fileOverwriteResult.isErr())
{
- ferr << "Failed to create project.conf: " << toFileString(fileOverwriteResult.getErrMsg()) << endl;
+ ferr << "Failed to create project file: " << toFileString(fileOverwriteResult.getErrMsg()) << endl;
exit(20);
}
}
@@ -494,6 +502,169 @@ Result<ExecResult> gitInitProject(const FileString &projectPath)
return exec(cmd.c_str());
}
+int initProject(int argc, const _tinydir_char_t **argv)
+{
+ if(argc > 2)
+ usageInit();
+
+ FileString projectPath;
+ const _tinydir_char_t *projectType = nullptr;
+
+ for(int i = 0; i < argc; ++i)
+ {
+ const _tinydir_char_t *arg = argv[i];
+ if(_tinydir_strcmp(arg, TINYDIR_STRING("--exec")) == 0)
+ {
+ if(projectType)
+ {
+ ferr << "Error: Project type was defined more than once. First as " << projectType << " then as " << arg << endl;
+ usageInit();
+ }
+ projectType = arg;
+ }
+ else if(_tinydir_strcmp(arg, TINYDIR_STRING("--static")) == 0)
+ {
+ if(projectType)
+ {
+ ferr << "Error: Project type was defined more than once. First as " << projectType << " then as " << arg << endl;
+ usageInit();
+ }
+ projectType = arg;
+ }
+ else if(_tinydir_strcmp(arg, TINYDIR_STRING("--dynamic")) == 0)
+ {
+ if(projectType)
+ {
+ ferr << "Error: Project type was defined more than once. First as " << projectType << " then as " << arg << endl;
+ usageInit();
+ }
+ projectType = arg;
+ }
+ else if(_tinydir_strncmp(arg, TINYDIR_STRING("--"), 2) == 0)
+ {
+ ferr << "Error: Invalid argument " << arg << endl;
+ usageInit();
+ }
+ else
+ {
+ if(!projectPath.empty())
+ {
+ ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl;
+ usageInit();
+ }
+ projectPath = arg;
+ }
+ }
+
+ if(!projectType)
+ {
+ ferr << "Error: Project type not defined, expected to be either --exec, --static or --dynamic" << endl;
+ usageInit();
+ }
+
+ string projectTypeConf;
+ if(_tinydir_strcmp(projectType, TINYDIR_STRING("--exec")) == 0)
+ projectTypeConf = "executable";
+ else if(_tinydir_strcmp(projectType, TINYDIR_STRING("--static")) == 0)
+ projectTypeConf = "static";
+ else if(_tinydir_strcmp(projectType, TINYDIR_STRING("--dynamic")) == 0)
+ projectTypeConf = "dynamic";
+ else
+ {
+ ferr << "Expected project type to be either --exec, --static or --dynamic; was: " << projectType << endl << endl;
+ usageInit();
+ }
+
+ // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found
+ if(projectPath.empty())
+ projectPath = TINYDIR_STRING(".");
+
+ validateDirectoryPath(projectPath.c_str());
+ if(projectPath.back() != '/')
+ projectPath += TINYDIR_STRING("/");
+
+ Result<FileString> projectRealPathResult = getRealPath(projectPath.c_str());
+ if(!projectRealPathResult)
+ {
+ ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl;
+ exit(40);
+ }
+ projectPath = projectRealPathResult.unwrap();
+
+ FileType projectFileType = getFileType(projectPath.c_str());
+ if(projectFileType == FileType::FILE_NOT_FOUND)
+ {
+ ferr << "Directory not found: '" << projectPath << "', unable to initialize project" << endl;
+ exit(20);
+ }
+ else if(projectFileType == FileType::REGULAR)
+ {
+ ferr << "Expected project path : '" << projectPath << "' to be a directory, was a file. Unable to initialize project" << endl;
+ exit(21);
+ }
+
+ const _tinydir_char_t *projectNameForwardSlash = findLastOf(projectPath.c_str(), projectPath.size(), '/');
+ const _tinydir_char_t *projectNameBackwardSlash = findLastOf(projectPath.c_str(), projectPath.size(), '\\');
+ string projectName;
+ if(projectNameForwardSlash && projectNameBackwardSlash)
+ {
+ if(projectNameForwardSlash > projectNameBackwardSlash)
+ projectName = toUtf8(projectNameForwardSlash + 1);
+ else
+ projectName = toUtf8(projectNameBackwardSlash + 1);
+ }
+ else if(!projectNameForwardSlash && projectNameBackwardSlash)
+ projectName = toUtf8(projectNameBackwardSlash + 1);
+ else if(!projectNameBackwardSlash && projectNameForwardSlash)
+ projectName = toUtf8(projectNameForwardSlash + 1);
+ else
+ projectName = toUtf8(projectPath);
+
+ if(!isProjectNameValid(projectName))
+ {
+ ferr << "Project name can only contain alphanumerical characters, dash (-) or underscore (_) and has to be longer than 0 characters" << endl;
+ exit(20);
+ }
+
+ auto createProjectConfResult = newProjectCreateConf(projectName, projectTypeConf, projectPath);
+ if(!createProjectConfResult)
+ {
+ ferr << "A project already exists in the directory " << projectPath << ". Error: failed to create project.conf, reason: " << createProjectConfResult.getErrMsg() << endl;
+ exit(20);
+ }
+ createDirectoryRecursive(projectPath + TINYDIR_STRING("/src"));
+ createDirectoryRecursive(projectPath + TINYDIR_STRING("/include"));
+ createDirectoryRecursive(projectPath + TINYDIR_STRING("/tests"));
+ if(projectTypeConf == "executable")
+ {
+ auto mainFilePath = projectPath + TINYDIR_STRING("/src/main.cpp");
+ Result<bool> fileOverwriteResult = fileWrite(mainFilePath.c_str(), "#include <cstdio>\n\nint main(int argc, char **argv)\n{\n printf(\"hello, world!\\n\");\n return 0;\n}\n");
+ if(!fileOverwriteResult)
+ fout << "Warning: Failed to create project file: " << toFileString(fileOverwriteResult.getErrMsg()) << endl;
+ }
+ gitInitProject(projectPath);
+ return 0;
+}
+
+void newProjectCreateMainDir(const FileString &projectPath)
+{
+ Result<bool> createProjectDirResult = createDirectoryRecursive(projectPath.c_str());
+ if(createProjectDirResult.isErr())
+ {
+ ferr << "Failed to create project main directory: " << toFileString(createProjectDirResult.getErrMsg()) << endl;
+ exit(20);
+ }
+}
+
+void checkFailCreateSubDir(Result<bool> createSubDirResult)
+{
+ if(!createSubDirResult)
+ {
+ ferr << "Failed to create directory in project: " << toFileString(createSubDirResult.getErrMsg()) << endl;
+ exit(20);
+ }
+}
+
int newProject(int argc, const _tinydir_char_t **argv)
{
if(argc != 2)
@@ -542,12 +713,25 @@ int newProject(int argc, const _tinydir_char_t **argv)
}
newProjectCreateMainDir(projectPath);
- newProjectCreateConf(projectName, projectTypeConf, projectPath);
- createProjectSubDir(projectPath + TINYDIR_STRING("/src"));
- createProjectSubDir(projectPath + TINYDIR_STRING("/include"));
- createProjectSubDir(projectPath + TINYDIR_STRING("/tests"));
+ auto createProjectConfResult = newProjectCreateConf(projectName, projectTypeConf, projectPath);
+ if(!createProjectConfResult)
+ {
+ ferr << "Failed to create project.conf: " << toFileString(createProjectConfResult.getErrMsg()) << endl;
+ exit(20);
+ }
+ createDirectoryRecursive(projectPath + TINYDIR_STRING("/src"));
+ createDirectoryRecursive(projectPath + TINYDIR_STRING("/include"));
+ createDirectoryRecursive(projectPath + TINYDIR_STRING("/tests"));
if(projectTypeConf == "executable")
- createProjectFile(projectPath + TINYDIR_STRING("/src/main.cpp"), "#include <cstdio>\n\nint main(int argc, char **argv)\n{\n printf(\"hello, world!\\n\");\n return 0;\n}\n");
+ {
+ auto mainFilePath = projectPath + TINYDIR_STRING("/src/main.cpp");
+ Result<bool> fileOverwriteResult = fileWrite(mainFilePath.c_str(), "#include <cstdio>\n\nint main(int argc, char **argv)\n{\n printf(\"hello, world!\\n\");\n return 0;\n}\n");
+ if(!fileOverwriteResult)
+ {
+ ferr << "Failed to create project file: " << toFileString(fileOverwriteResult.getErrMsg()) << endl;
+ exit(20);
+ }
+ }
// We are ignoring git init result on purpose. If it fails, just ignore it; not important
gitInitProject(projectPath);
return 0;
@@ -579,6 +763,10 @@ int wmain(int argc, const _tinydir_char_t **argv)
{
return testProject(subCommandArgCount, subCommandArgPtr);
}
+ else if(_tinydir_strcmp(arg, TINYDIR_STRING("init")) == 0)
+ {
+ return initProject(subCommandArgCount, subCommandArgPtr);
+ }
else
{
ferr << "Expected command to be either 'build', 'new' or 'test', was: " << arg << endl << endl;