void repository::distributor::update_meta(const entry &package) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; const tempfile checksum_tmp = local_system_().small_tempfile(); try { m_fetcher->fetch(checksum_url(package), checksum_tmp.path()); } catch (std::exception &) { BOOST_THROW_EXCEPTION( distributor_update_meta_no_package_error() << distributor_update_meta_no_package_error::path(checksum_tmp.path()) << distributor_update_meta_no_package_error::message( "Unable to fetch checksum") << enable_nested_current()); } boost::filesystem::copy_file( checksum_tmp.path(), cache_().checksum_path(package), boost::filesystem::copy_option::overwrite_if_exists); update_file(index_url(package), cache_().index_path(package), // \pre index is treated like regular source cache_().read_checksum(package).at(format().name.get_index())); } catch (std::exception &) { BOOST_THROW_EXCEPTION(distributor_update_meta_error() << distributor_update_meta_error::package(package) << enable_nested_current()); } }
void repository::extractor::install( const entry &package, const boost::filesystem::path &destination) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; const boost::filesystem::path meta = destination / m_config.installation.meta; const boost::filesystem::path snp = cache_().installation_snapshot_path(package); boost::filesystem::path dst = destination; if (m_config.installation.data) dst /= m_config.installation.data.get(); bunsan::filesystem::reset_dir(destination); extract(package, dst); if (boost::filesystem::exists(meta)) { BOOST_ASSERT(!m_config.installation.data); BOOST_THROW_EXCEPTION(installation_meta_exists_error() << installation_meta_exists_error::meta(meta)); } boost::filesystem::copy_file( snp, meta, boost::filesystem::copy_option::fail_if_exists); boost::filesystem::last_write_time(meta, std::time(nullptr)); } catch (std::exception &) { BOOST_THROW_EXCEPTION(extractor_install_error() << extractor_install_error::package(package) << extractor_install_error::destination(destination) << enable_nested_current()); } }
void repository::builder::build(const entry &package) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; const tempfile build_dir_ = local_system_().tempdir_for_build(); const boost::filesystem::path build_dir = build_dir_.path(); const boost::filesystem::path src = build_dir / m_config.name.dir.get_source(); const boost::filesystem::path build = build_dir / m_config.name.dir.get_build(); const boost::filesystem::path installation = build_dir / m_config.name.dir.get_installation(); // create/clean directories boost::filesystem::create_directory(src); boost::filesystem::create_directory(build); boost::filesystem::create_directory(installation); // unpack source snapshot snapshot_; unpack_source(package, src, snapshot_); get_builder()->install(build_dir / m_config.name.dir.get_source(), build_dir / m_config.name.dir.get_build(), build_dir / m_config.name.dir.get_installation()); cache_().pack_build(package, build_dir / m_config.name.dir.get_installation()); write_snapshot(cache_().build_snapshot_path(package), snapshot_); } catch (std::exception &) { BOOST_THROW_EXCEPTION(builder_build_error() << builder_build_error::package(package) << enable_nested_current()); } }
void repository::cache::verify_and_repair_directory( const boost::filesystem::path &path) { try { if (!path.is_absolute()) BOOST_THROW_EXCEPTION( invalid_configuration_relative_path_error() << invalid_configuration_relative_path_error::path(path)); BUNSAN_LOG_TRACE << "Checking " << path; if (!boost::filesystem::is_directory(path)) { if (!boost::filesystem::exists(path)) { BUNSAN_LOG_ERROR << "Directory " << path << " was not found"; } else { BUNSAN_LOG_ERROR << path << " is not a directory: starting recursive remove"; boost::filesystem::remove_all(path); } if (boost::filesystem::create_directory(path)) BUNSAN_LOG_TRACE << "Created missing " << path << " directory"; } } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_verify_and_repair_directory_error() << cache_verify_and_repair_directory_error::path(path) << enable_nested_current()); } }
void repository::builder::build_installation(const entry &package) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; const tempfile build_dir = local_system_().tempdir_for_build(); boost::filesystem::path install_dir = build_dir.path() / m_config.name.dir.get_installation(); // unpack extractor_().extract_build(package, install_dir); snapshot snapshot_ = cache_().read_build_snapshot(package); const index deps = cache_().read_index(package); for (const auto &i : deps.package.self) extractor_().extract_source(package, i.source, install_dir / i.path); for (const auto &i : deps.package.import.source) unpack_source(i.package, install_dir / i.path, snapshot_); for (const auto &i : deps.package.import.package) { extractor_().extract_installation(i.package, install_dir / i.path); merge_maps(snapshot_, cache_().read_installation_snapshot(i.package)); } // save cache_().pack_installation(package, install_dir); write_snapshot(cache_().installation_snapshot_path(package), snapshot_); } catch (std::exception &) { BOOST_THROW_EXCEPTION(builder_build_installation_error() << builder_build_installation_error::package(package) << enable_nested_current()); } }
void repository::cache::initialize(const cache_config &config) { try { if (!config.root.is_absolute()) BOOST_THROW_EXCEPTION( invalid_configuration_relative_path_error() << invalid_configuration_relative_path_error::path(config.root)); // ignore if directory exists boost::filesystem::create_directory(config.root); boost::filesystem::create_directory(config.get_source()); boost::filesystem::create_directory(config.get_package()); // lock if (!config.get_lock().is_absolute()) BOOST_THROW_EXCEPTION(invalid_configuration_relative_path_error() << invalid_configuration_relative_path_error::path( config.get_lock())); if (boost::filesystem::exists(config.get_lock())) { if (!boost::filesystem::is_regular_file(config.get_lock())) boost::filesystem::remove(config.get_lock()); } if (!boost::filesystem::exists(config.get_lock())) { filesystem::ofstream fout(config.get_lock()); fout.close(); } initialize_meta(config); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_initialize_error() << enable_nested_current()); } }
void repository::cache::verify_and_repair() { try { bool outdated = false; try { const auto meta = load_meta(); if (meta.version != repository::version()) { BUNSAN_LOG_INFO << "Cache's version \"" << meta.version << "\" is not equal to repository's version \"" << repository::version() << "\", resetting cache"; outdated = true; } } catch (std::exception &) { BUNSAN_LOG_ERROR << "Unable to read cache's meta, resetting cache"; outdated = true; } if (outdated) { clean_(); save_meta(); } verify_and_repair_directory(m_config.get_source()); verify_and_repair_directory(m_config.get_package()); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_verify_and_repair_error() << enable_nested_current()); } }
boost::filesystem::path find_executable_in_path( const boost::filesystem::path &executable) { try { if (executable != executable.filename()) BOOST_THROW_EXCEPTION( non_basename_executable_error() << non_basename_executable_error::executable(executable)); const boost::filesystem::path exts[] = {"", ".exe", ".com", ".bat"}; for (const auto &ext : exts) { wchar_t buf[MAX_PATH]; LPWSTR dummy; const DWORD size = ::SearchPathW(nullptr, executable.c_str(), ext.c_str(), MAX_PATH, buf, &dummy); BOOST_ASSERT(size < MAX_PATH); if (size > 0) return buf; } BOOST_THROW_EXCEPTION( no_executable_in_path_error() << no_executable_in_path_error::executable(executable)); } catch (find_executable_in_path_error &) { throw; } catch (std::exception &) { BOOST_THROW_EXCEPTION( find_executable_in_path_error() << find_executable_in_path_error::executable(executable) << enable_nested_current()); } }
void repository::extractor::update(const entry &package, const boost::filesystem::path &destination) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; const boost::filesystem::path meta = destination / m_config.installation.meta; boost::optional<snapshot> snapshot_; if (boost::filesystem::is_regular_file(meta)) { try { snapshot_ = read_snapshot(meta); } catch (std::exception &) { BUNSAN_LOG_WARNING << "Unable to read snapshot from " << meta << ", falling back to outdated"; } } if (!snapshot_ || *snapshot_ != cache_().read_installation_snapshot(package)) { BUNSAN_LOG_DEBUG << "\"" << package << "\" installation at " << destination << " is outdated, updating..."; install(package, destination); } else { boost::filesystem::last_write_time(meta, std::time(nullptr)); } } catch (std::exception &) { BOOST_THROW_EXCEPTION(extractor_update_error() << extractor_update_error::package(package) << extractor_update_error::destination(destination) << enable_nested_current()); } }
void repository::distributor::create_recursively( const boost::filesystem::path &root, const bool strip) { try { std::unordered_set<std::string> ignore; const boost::filesystem::path index_path = root / format().name.get_index(); if (boost::filesystem::is_regular_file(index_path)) { BUNSAN_LOG_DEBUG << "Found index file at " << root << ", trying to create source package..."; ignore.insert(format().name.get_index()); create(root, strip); index index_; index_.load(index_path); const std::unordered_set<std::string> sources = index_.sources(); ignore.insert(sources.begin(), sources.end()); } for (boost::filesystem::directory_iterator i(root), end; i != end; ++i) { if (boost::filesystem::is_directory(*i) && ignore.find(i->path().filename().string()) == ignore.end()) { create_recursively(i->path(), strip); } } } catch (distributor_create_recursively_error &) { throw; } catch (std::exception &) { BOOST_THROW_EXCEPTION(distributor_create_recursively_error() << distributor_create_recursively_error::root(root) << distributor_create_recursively_error::strip(strip) << enable_nested_current()); } }
void repository::cache::clean_() { try { filesystem::reset_dir(m_config.get_source()); filesystem::reset_dir(m_config.get_package()); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_clean_error() << enable_nested_current()); } }
void NamedLogWriter::append(const boost::filesystem::path &path) { try { open_(path, true); } catch (std::exception &) { BOOST_THROW_EXCEPTION(NamedLogWriterAppendError() << enable_nested_current()); } }
index repository::cache::read_index(const entry &package) { try { return index(index_path(package)).absolute(package); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_read_index_error() << cache_read_index_error::package(package) << enable_nested_current()); } }
void NamedLogWriter::reopen() { try { reopen(path_); } catch (std::exception &) { BOOST_THROW_EXCEPTION(NamedLogWriterReopenError() << enable_nested_current()); } }
snapshot_entry repository::cache::read_checksum(const entry &package) { try { return pm::read_checksum(checksum_path(package)); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_read_checksum_error() << cache_read_checksum_error::package(package) << enable_nested_current()); } }
snapshot repository::cache::read_installation_snapshot(const entry &package) { try { return read_snapshot(installation_snapshot_path(package)); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_read_installation_snapshot_error() << cache_read_installation_snapshot_error::package( package) << enable_nested_current()); } }
void repository::cache::clean() { try { verify_and_repair(); clean_(); } catch (cache_clean_error &) { throw; } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_clean_error() << enable_nested_current()); } }
void repository::cache::unpack_build( const entry &package, const boost::filesystem::path &destination) { try { m_archiver->unpack(build_archive_path(package), destination); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_unpack_build_error() << cache_unpack_build_error::package(package) << cache_unpack_build_error::destination(destination) << enable_nested_current()); } }
void repository::cache::pack_installation(const entry &package, const boost::filesystem::path &path) { try { m_archiver->pack_contents(installation_archive_path(package), path); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_pack_installation_error() << cache_pack_installation_error::package(package) << cache_pack_installation_error::path(path) << enable_nested_current()); } }
void repository::extractor::extract_build( const entry &package, const boost::filesystem::path &destination) { try { const tempfile tmp = local_system_().tempdir_for_build(); cache_().unpack_build(package, tmp.path()); merge_directories(tmp.path(), destination); } catch (std::exception &) { BOOST_THROW_EXCEPTION(extractor_extract_build_error() << extractor_extract_build_error::package(package) << extractor_extract_build_error::destination( destination) << enable_nested_current()); } }
void repository::extractor::extract( const entry &package, const boost::filesystem::path &destination) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; filesystem::reset_dir(destination); cache_().unpack_installation(package, destination); } catch (std::exception &) { BOOST_THROW_EXCEPTION(extractor_extract_error() << extractor_extract_error::package(package) << extractor_extract_error::destination(destination) << enable_nested_current()); } }
void NamedLogWriter::reopen(const boost::filesystem::path &newPath) { try { if (!hasOutput()) { BOOST_THROW_EXCEPTION(ClosedWriterError()); } close(); open(newPath); } catch (std::exception &) { BOOST_THROW_EXCEPTION(NamedLogWriterReopenError() << enable_nested_current()); } }
void repository::cache::unpack_source( const entry &package, const std::string &source_id, const boost::filesystem::path &destination) { try { distributor_().archiver().unpack(source_path(package, source_id), destination); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_unpack_source_error() << cache_unpack_source_error::package(package) << cache_unpack_source_error::destination(destination) << enable_nested_current()); } }
void cwd_split::pack(const boost::filesystem::path &archive, const boost::filesystem::path &file) { try { const boost::filesystem::path file_ = boost::filesystem::absolute(file); const boost::filesystem::path archive_ = boost::filesystem::absolute(archive); pack_from(file_.parent_path(), archive_, file_.filename()); } catch (std::exception &) { BOOST_THROW_EXCEPTION(archiver_pack_error() << archiver_pack_error::archive(archive) << archiver_pack_error::file(file) << enable_nested_current()); } }
void NamedLogWriter::rotate(const boost::filesystem::path &renameTo) { try { if (!hasOutput()) { BOOST_THROW_EXCEPTION(ClosedWriterError()); } close(); boost::filesystem::rename(path_, renameTo); open(path_); } catch (std::exception &) { BOOST_THROW_EXCEPTION(NamedLogWriterRotateError() << enable_nested_current()); } }
/// \return false if !closed() void open(const boost::filesystem::path &path) { try { if (!closed()) { BOOST_THROW_EXCEPTION(OpenedError()); } path_ = path; stream_ = openFd(path, errno_); checkError(); } catch (std::exception &) { BOOST_THROW_EXCEPTION(OpenError() << enable_nested_current()); } }
bool repository::cache::build_outdated(const entry &package, const snapshot &snapshot_) { try { const boost::filesystem::path snp = build_snapshot_path(package); const boost::filesystem::path build = build_archive_path(package); if (!boost::filesystem::exists(snp) || !boost::filesystem::exists(build)) return true; return snapshot_ != read_snapshot(snp); } catch (std::exception &) { BOOST_THROW_EXCEPTION(cache_build_outdated_error() << cache_build_outdated_error::package(package) << enable_nested_current()); } }
void repository::builder::build_empty(const entry &package) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; const tempfile build_dir = local_system_().tempdir_for_build(); // create empty archive cache_().pack_build(package, build_dir.path()); const snapshot snapshot_ = {{package, cache_().read_checksum(package)}}; write_snapshot(cache_().build_snapshot_path(package), snapshot_); } catch (std::exception &) { BOOST_THROW_EXCEPTION(builder_build_empty_error() << builder_build_empty_error::package(package) << enable_nested_current()); } }
void repository::distributor::update_sources(const entry &package) { try { BUNSAN_LOG_DEBUG << "Starting \"" << package << "\" " << __func__; for (const std::string &src_name : cache_().read_index(package).sources()) { update_file(source_url(package, src_name), cache_().source_path(package, src_name), cache_().read_checksum(package).at(src_name)); } } catch (std::exception &) { BOOST_THROW_EXCEPTION(distributor_update_sources_error() << distributor_update_sources_error::package(package) << enable_nested_current()); } }
void repository::distributor::create(const boost::filesystem::path &source, bool strip) { try { const boost::filesystem::path index_name = source / format().name.get_index(); const boost::filesystem::path checksum_name = source / format().name.get_checksum(); snapshot_entry checksum; // we need to save index checksum checksum[format().name.get_index()] = pm::checksum(index_name); std::unordered_set<std::string> to_remove; index index_; index_.load(index_name); for (const std::string &src_name : index_.sources()) { const std::string src_value = src_name + format().name.suffix.archive; const boost::filesystem::path src = source / src_name; const boost::filesystem::path dst = boost::filesystem::absolute(source / src_value); if (!boost::filesystem::exists(src)) BOOST_THROW_EXCEPTION(source_does_not_exist_error() << source_does_not_exist_error::source(src_name) << source_does_not_exist_error::path(src)); m_archiver->pack_contents(dst, src); checksum[src_name] = pm::checksum(source / src_value); to_remove.insert(src_name); // we will remove all sources } { boost::property_tree::ptree checksum_; for (const auto &i : checksum) checksum_.put(boost::property_tree::ptree::path_type(i.first, '\0'), i.second); boost::property_tree::write_info(checksum_name.string(), checksum_); } // we will remove all files at the end to provide exception guarantee // that we will not remove anything accidentally if (strip) for (const std::string &i : to_remove) { boost::filesystem::path path = source / i; BUNSAN_LOG_DEBUG << "Removing excess file from source package: " << path; boost::filesystem::remove_all(path); } } catch (std::exception &) { BOOST_THROW_EXCEPTION(distributor_create_error() << distributor_create_error::source(source) << distributor_create_error::strip(strip) << enable_nested_current()); } }