Skip to content
This repository has been archived by the owner on Jan 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #33 from AntelopeIO/sbailey/escape_compiler_and_li…
Browse files Browse the repository at this point in the history
…nk_options

Allow for escaped compiler and link optional parameters
  • Loading branch information
ScottBailey authored Apr 13, 2023
2 parents 1b274aa + 8778970 commit 29f3013
Show file tree
Hide file tree
Showing 8 changed files with 817 additions and 26 deletions.
621 changes: 621 additions & 0 deletions .pylintrc

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ if (ANTLER_PROJ_BUILD_TESTS)
# TODO renable when add to test code is completed:
#add_cli_test(add_to_project_tests add_to_tests.py)
add_cli_test(init_tests init_tests.py)
add_cli_test(add_and_update add_and_update.py)
endif()
16 changes: 9 additions & 7 deletions tools/add_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace antler {
system::info_log("Valid names are of the form [a-zA-Z][_a-zA-Z0-9]+");
return false;
}

// TODO for the next release we will remove the C++ restrictions
const auto& is_valid_cpp_lang = [](auto l) {
return l == "cpp" ||
Expand Down Expand Up @@ -115,7 +115,7 @@ namespace antler {
system::error_log("Dependency: {0} is invalid.", dep_name);
return false;
}

obj.upsert_dependency(std::move(dep));

// We have values, so query the user if they want to apply.
Expand Down Expand Up @@ -147,8 +147,10 @@ namespace antler {
app_subcommand = subcommand->add_subcommand("app", "Add a new app to your project.");
app_subcommand->add_option("-n, name", obj_name, "The name of the app to add.")->required();
app_subcommand->add_option("-l, lang", lang, "Language this app will use.")->required();
app_subcommand->add_option("--comp, compile_options", copts, "Options for the compiler for this app.");
app_subcommand->add_option("--link, link_options", lopts, "Options for the linker for this app.");
app_subcommand->add_option("--comp, compile_options", copts, "Options for the compiler for this app.")
->transform(escape_transform);
app_subcommand->add_option("--link, link_options", lopts, "Options for the linker for this app.")
->transform(escape_transform);

lib_subcommand = subcommand->add_subcommand("lib", "Add a new library to your project.");
lib_subcommand->add_option("-n, name", obj_name, "The name of the library to add.")->required();
Expand All @@ -163,7 +165,7 @@ namespace antler {
dep_subcommand->add_option("-t, tag", tag, "Tag associated with the dependency.");
dep_subcommand->add_option("-r, release", release, "Release version of the depedency.");
dep_subcommand->add_option("--digest, hash", hash, "Hash of the dependency.");

/* TODO Add back after this release when we have the testing framework finished
test_subcommand = subcommand->add_subcommand("test", "Add a new test to the project.");
test_subcommand->add_option("-n, name", obj_name, "The name of the test to add.")->required();
Expand Down Expand Up @@ -198,7 +200,7 @@ namespace antler {
proj.sync();
return 0;
}

CLI::App* subcommand;
CLI::App* app_subcommand;
CLI::App* dep_subcommand;
Expand All @@ -216,4 +218,4 @@ namespace antler {
std::string lopts;
std::string cmd;
};
} // namespace antler
} // namespace antler
19 changes: 17 additions & 2 deletions tools/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,28 @@

namespace antler {

/// Remove escape sequence character from input.
/// @note This is a SIMPLE algorithm that ONLY removes the first `\` in a 2 charachter sequence.
/// @todo Consider implementing more complicated transforms (e.g. convert "\t" to 0x09 or "\xFF" to 0xFF, etc).
/// @param input Input string that may or may not contain escape characters.
/// @return The transformed string.
std::string escape_transform(std::string input) {
for(auto i=input.begin(); i != input.end(); ++i) {
// Only remove this char *if* there is a char following.
// Note: erase plus increment effectively steps over the char follwing the erased `\` (e.g. "\\-O2" becomes "\-O2").
if(*i == '\\' && i+1 != input.end())
i = input.erase(i);
}
return input;
}

inline project::project load_project(const system::fs::path& path) {
auto p = system::fs::canonical(system::fs::path(path));
ANTLER_CHECK(project::project::update_path(p),
"path either did not exist or no `project.yml` file cound be found.");
project::project proj;
ANTLER_CHECK(proj.from_yaml(project::yaml::load(p)),
"error while loading project.yml file");
"error while loading project.yml file");
proj.path(p.parent_path());
return proj;
}
Expand All @@ -32,4 +47,4 @@ namespace antler {

return last_pop_time < last_manifest_time;
}
}
}
136 changes: 136 additions & 0 deletions tools/tests/add_and_update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#! /usr/bin/env python3

""" Test `antler-proj add` and `antler proj update` commands. """

import os
import shutil

from util import antler_in_proj_cmd, load_project
from init_tests import init_project

PROJECT_NAME="aou_project"
PROJECT_PATH=os.path.join("./",PROJECT_NAME)

def expect_subvalue(array_of_lists, name, tag, value):
""" Inside array_of_lists, find the list that contains `name` and test the value
stored in that list for the given tag against value.
:param array_of_lists An array of lists.
:param name The name to search for.
:tag The tag that contains the value we to test.
:value The expected value.
"""

for i in array_of_lists:
if i["name"] == name:
return i[tag] == value
return False


def setup_project():
"""Setup the project ensuring there is a fresh project file.
"""

shutil.rmtree(PROJECT_PATH, ignore_errors=True)
init_project(PROJECT_NAME, "v1.0.0", PROJECT_PATH)
assert os.path.isdir(PROJECT_PATH)


def test_app_compile_options():
"""Add an application to the project and test its compile options can be updated.
"""

out, _ = antler_in_proj_cmd(PROJECT_PATH, "add app App1 C++ \\\\-O1")
print(out)
project = load_project(PROJECT_PATH)
assert expect_subvalue(project["apps"], "App1", "compile_options", "-O1")

out, _ = antler_in_proj_cmd(PROJECT_PATH, "update app App1 C++ \\\\-O2")
print(out)
project = load_project(PROJECT_PATH)
assert expect_subvalue(project["apps"], "App1", "compile_options", "-O2")


def test_app_link_options():
"""Add an application to the project and test its compile and link options can be updated.
"""

out, _ = antler_in_proj_cmd(PROJECT_PATH, "add app App2 C++ \"\\-O1\" \\\\-t")
print(out)
project = load_project(PROJECT_PATH)
assert expect_subvalue(project["apps"], "App2", "compile_options", "-O1")
assert expect_subvalue(project["apps"], "App2", "link_options", "-t")

out, _ = antler_in_proj_cmd(PROJECT_PATH, "update app App2 C++ \"\\-O2\" \\\\-s")
print(out)
project = load_project(PROJECT_PATH)
assert expect_subvalue(project["apps"], "App2", "compile_options", "-O2")
assert expect_subvalue(project["apps"], "App2", "link_options", "-s")


def test_app_update_options():
"""Add an application to the project and test its compile and link options
can be updated with flags.
"""

out, _ = antler_in_proj_cmd(PROJECT_PATH, "add app App3 C++")
print(out)
project = load_project(PROJECT_PATH)
assert expect_subvalue(project["apps"], "App3", "compile_options", "")
assert expect_subvalue(project["apps"], "App3", "link_options", "")

out, _ = antler_in_proj_cmd(PROJECT_PATH, "update app App3 --comp \\\\-O1")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["apps"], "App3", "compile_options", "-O1")
out, _ = antler_in_proj_cmd(PROJECT_PATH, "update app App3 --comp \"\\-O2\"")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["apps"], "App3", "compile_options", "-O2")

out, _ = antler_in_proj_cmd(PROJECT_PATH, "update app App3 --link \\\\-s")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["apps"], "App3", "link_options", "-s")
out, _ = antler_in_proj_cmd(PROJECT_PATH, "update app App3 --link \"\\-t\"")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["apps"], "App3", "link_options", "-t")

assert expect_subvalue(load_project(PROJECT_PATH)["apps"], "App3", "compile_options", "-O2")


def test_lib_options():
"""Add a library to the project and test its compile and link options can be updated with flags.
"""

out, _ = antler_in_proj_cmd(PROJECT_PATH, "add lib Lib1 C++")
print(out)
project = load_project(PROJECT_PATH)
assert expect_subvalue(project["libs"], "Lib1", "compile_options", "")
assert expect_subvalue(project["libs"], "Lib1", "link_options", "")

out, _ = antler_in_proj_cmd(PROJECT_PATH, "update lib Lib1 --comp -O1")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["libs"], "Lib1", "compile_options", "-O1")
out, _ = antler_in_proj_cmd(PROJECT_PATH, "update lib Lib1 --comp \"-O2\"")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["libs"], "Lib1", "compile_options", "-O2")

out, _ = antler_in_proj_cmd(PROJECT_PATH, "update lib Lib1 --link -s")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["libs"], "Lib1", "link_options", "-s")
out, _ = antler_in_proj_cmd(PROJECT_PATH, "update lib Lib1 --link \"-t\"")
print(out)
assert expect_subvalue(load_project(PROJECT_PATH)["libs"], "Lib1", "link_options", "-t")

assert expect_subvalue(load_project(PROJECT_PATH)["libs"], "Lib1", "compile_options", "-O2")





if __name__ == "__main__":
setup_project()
test_app_compile_options()
test_app_link_options()
test_app_update_options()
test_lib_options()
1 change: 1 addition & 0 deletions tools/tests/init_tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#! /usr/bin/env python3

import sys
import shutil

from util import *

Expand Down
33 changes: 23 additions & 10 deletions tools/tests/util.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
#! /usr/bin/env python3

"""Utility functions for antler-proj testing."""

import subprocess
import os
import yaml
import shutil

TEST_PATH = os.path.dirname(os.path.abspath(__file__))
APROJ_EXE = TEST_PATH + "/../antler-proj"

def run_cmd(cmd):
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
""" Execute `cmd`. """
result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = result.communicate()
return out.decode('utf-8'), err.decode('utf-8')

def antler_proj_cmd(args):
return run_cmd("../antler-proj " + args)
""" Run antler-proj with `args`. """
return run_cmd(APROJ_EXE + " " + args)

def antler_in_proj_cmd(path, args):
""" Change directory to `path` and run antler-proj with `args`. """
return run_cmd("cd " + path + "; " + APROJ_EXE + " " + args)

def load_project(path):
with open("./{0}/project.yml".format(path), "r") as f:
project = yaml.safe_load(f)
""" Load a project.yml file """
with open("./{0}/project.yml".format(path), "r") as file_handle:
project = yaml.safe_load(file_handle)
return project

def expected_cmd(cmd, expected):
out, err = run_cmd(cmd)
""" Test that cmd has an expected result. """
out, _ = run_cmd(cmd)
if out != expected:
print("ERROR: cmd: %s != expected: %s" % (cmd, expected))
assert(False)
assert False

def expected_proj_cmd(cmd, expected):
out, err = antler_proj_cmd(cmd)
""" Test that `antler-proj cmd` has an expected result. """
out, _ = antler_proj_cmd(cmd)
if out != expected:
print("ERROR: cmd: %s != expected: %s" % (cmd, expected))
assert(False)
assert False
16 changes: 9 additions & 7 deletions tools/update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace antler {
obj.compile_options(copts);
if (!lopts_opt->empty())
obj.link_options(lopts);

system::info_log("Updating object: {0}\n"
"language: {1}\n"
"compile options: {2}\n"
Expand All @@ -42,7 +42,7 @@ namespace antler {
obj.language(),
copts,
lopts);

return true;
} catch(...) {
system::error_log("Object {0} does not exist in the project", obj_name);
Expand Down Expand Up @@ -115,8 +115,10 @@ namespace antler {
app_subcommand = subcommand->add_subcommand("app", "Remove app from the project.");
app_subcommand->add_option("-n, name", obj_name, "The name of the app to remove.")->required();
app_subcommand->add_option("-l, language", lang, "The language of the app.");
app_subcommand->add_option("--comp, compile_options", copts, "The compile options used to build the app.");
app_subcommand->add_option("--link, link_options", lopts, "The link options used to build the app.");
app_subcommand->add_option("--comp, compile_options", copts, "The compile options used to build the app.")
->transform(escape_transform);
app_subcommand->add_option("--link, link_options", lopts, "The link options used to build the app.")
->transform(escape_transform);

lib_subcommand = subcommand->add_subcommand("lib", "Remove lib from the project.");
lib_subcommand->add_option("-n, name", obj_name, "The name of the library to add.")->required();
Expand All @@ -136,7 +138,7 @@ namespace antler {
test_subcommand = subcommand->add_subcommand("test", "Remove a test from the project.");
test_subcommand->add_option("-n, name", dep_name, "The name of the test to remove.")->required();
*/

}

int32_t exec() {
Expand Down Expand Up @@ -167,7 +169,7 @@ namespace antler {
proj.sync();
return 0;
}

CLI::App* subcommand = nullptr;
CLI::App* app_subcommand = nullptr;
CLI::App* dep_subcommand = nullptr;
Expand All @@ -184,4 +186,4 @@ namespace antler {
std::string release = "";
std::string digest = "";
};
} // namespace antler
} // namespace antler

0 comments on commit 29f3013

Please sign in to comment.