Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions include/cppship/cmd/build.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ struct BuildContext {
}
}

[[nodiscard]] bool is_expired(const fs::path& path) const
{
return !fs::exists(path) || fs::last_write_time(path) < fs::last_write_time(metafile);
}
[[nodiscard]] bool is_expired(const fs::path& path) const;
};

int run_build(const BuildOptions& options);
Expand Down
4 changes: 2 additions & 2 deletions include/cppship/util/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace cppship {

void write(const fs::path& file, std::string_view content);

inline void touch(const fs::path& file) { write(file, ""); }
void touch(const fs::path& file);

std::string read_as_string(const fs::path& file);

std::string read_as_string(std::istream& iss);

}
}
19 changes: 19 additions & 0 deletions lib/cmd/build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/concat.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/map.hpp>
#include <range/v3/view/transform.hpp>
#include <spdlog/spdlog.h>
#include <toml.hpp>
Expand All @@ -29,6 +30,7 @@
#include "cppship/core/layout.h"
#include "cppship/core/resolver.h"
#include "cppship/exception.h"
#include "cppship/util/assert.h"
#include "cppship/util/cmd.h"
#include "cppship/util/fs.h"
#include "cppship/util/git.h"
Expand All @@ -41,6 +43,23 @@ using namespace fmt::literals;

namespace rng = ranges::views;

bool cmd::BuildContext::is_expired(const fs::path& path) const
{
if (!fs::exists(path)) {
return true;
}
if (fs::last_write_time(path) < fs::last_write_time(metafile)) {
return true;
}

const auto manifest_last_update_times = rng::keys(workspace) | rng::transform([](const fs::path& package_dir) {
return fs::last_write_time(package_dir / kRepoConfigFile);
});
enforce(!manifest_last_update_times.empty(), "at least one manifest should exists");

return fs::last_write_time(path) < *ranges::max_element(manifest_last_update_times);
}

int cmd::run_build(const BuildOptions& options)
{
BuildContext ctx(options.profile);
Expand Down
20 changes: 17 additions & 3 deletions lib/util/io.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include "cppship/util/io.h"
#include "cppship/exception.h"

#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>

#include "cppship/exception.h"
#include "cppship/util/fs.h"

void cppship::write(const fs::path& file, std::string_view content)
{
std::ofstream ofs(file);
Expand All @@ -21,6 +23,17 @@ void cppship::write(const fs::path& file, std::string_view content)
}
}

void cppship::touch(const fs::path& file)
{
if (!fs::exists(file)) {
std::ofstream ofs(file);
ofs.close();
return;
}

fs::last_write_time(file, fs::file_time_type::clock::now());
}

std::string cppship::read_as_string(const fs::path& file)
{
try {
Expand All @@ -34,12 +47,13 @@ std::string cppship::read_as_string(const fs::path& file)
std::string cppship::read_as_string(std::istream& iss)
{
std::ostringstream oss;
std::copy(std::istreambuf_iterator<char> { iss }, std::istreambuf_iterator<char> {},
std::copy(std::istreambuf_iterator<char> { iss },
std::istreambuf_iterator<char> {},
std::ostreambuf_iterator<char> { oss });

if (!iss || !oss) {
throw IOError { "drain stream failed" };
}

return oss.str();
}
}
93 changes: 93 additions & 0 deletions tests/cmd/build.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "cppship/cmd/build.h"

#include <gtest/gtest.h>

#include "cppship/core/profile.h"
#include "cppship/util/io.h"

namespace cppship {

class DirTree {
public:
explicit DirTree(const std::set<std::string_view>& trees)
{
fs::create_directory(mRoot);
fs::current_path(mRoot);

for (const auto& path : trees) {
fs::path fs_path { path };

if (path.ends_with('/')) {
fs::create_directories(fs_path);
} else {
const auto parent = fs_path.parent_path();
if (!parent.empty()) {
fs::create_directories(fs_path.parent_path());
}
std::ofstream ofs(fs_path);
}
}
}

~DirTree()
{
fs::current_path(mOriPath);
fs::remove_all(mRoot);
}

const fs::path& root() const { return mRoot; }

std::string relative(const fs::path& path)
{
// use generic_string to deal with windows
return path.lexically_relative(mRoot).generic_string();
}

private:
fs::path mRoot = fs::temp_directory_path() / "cppship.test";
fs::path mOriPath = fs::current_path();
};

TEST(build, is_expired)
{
const std::set<std::string_view> package_manifests = {
"cppship.toml",
"package-1/cppship.toml",
"dir/package-2/cppship.toml",
"dir/package-3/cppship.toml",
};
DirTree tree(package_manifests);

write(tree.root() / "cppship.toml", R"(
[workspace]
members = ["package-1", "dir/package-2", "dir/package-3"])");
write(tree.root() / "package-1/cppship.toml", R"(
[package]
version = "1.0.0"
name = "p1")");
write(tree.root() / "dir/package-2/cppship.toml", R"(
[package]
version = "1.0.0"
name = "p2")");
write(tree.root() / "dir/package-3/cppship.toml", R"(
[package]
version = "1.0.0"
name = "p3")");

const auto test_file = tree.root() / "test";
cmd::BuildContext ctx(Profile::debug);
ASSERT_TRUE(ctx.is_expired(test_file));

touch(test_file);
ASSERT_TRUE(!ctx.is_expired(test_file));

for (const auto manifest : package_manifests) {
touch(manifest);
ASSERT_TRUE(ctx.is_expired(test_file));

touch(test_file);
ASSERT_TRUE(!ctx.is_expired(test_file));
}
}

}