Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
844c5b8
Fix clang-format violations
jezdez Apr 10, 2026
d88fa4d
Address exclude-newer review feedback
jezdez Jun 8, 2026
40cfc6b
feat: Wire global exclude_newer config and CLI to solver
jjerphan Jun 10, 2026
386634f
Remove useless `static_cast`
jjerphan Jun 10, 2026
407996e
Do not pass the context's instance
jjerphan Jun 10, 2026
4ec42c7
Support `exclude_newer_package`
jjerphan Jun 10, 2026
59fff4d
Use custom regex match for string_view
jjerphan Jun 10, 2026
f614ddc
Rename to and use `ExcludeNewerPolicy`
jjerphan Jun 16, 2026
376768b
Replace `trim` in preference of `util::strip_if`
jjerphan Jun 16, 2026
9c03ead
Include missing header file in libmamba sources list
jjerphan Jun 16, 2026
d005385
Minor adaptations to utility functions
jjerphan Jun 16, 2026
d669e92
Add tests for `{CONDA,MAMBA}_EXCLUDE_NEWER{,_PACKAGE}`
jjerphan Jun 16, 2026
12c7fb6
Test abscence of `timestamp` and `indexed_timestamp`
jjerphan Jun 16, 2026
bdc7805
Test `exclude_newer{,_package}` further
jjerphan Jun 16, 2026
815bc46
Reorder files in sources lists
jjerphan Jun 17, 2026
bd81f34
Remove leftover field
jjerphan Jun 30, 2026
af68afd
Use elements of `std::chrono` and apply review comments
jjerphan Jun 30, 2026
469745f
Name and type `exclude_newer_*` parameters
jjerphan Jun 30, 2026
dde5a93
Adapt and test ISO 8601 durations parsing
jjerphan Jun 30, 2026
4ad4d33
Adapt and test compact duration parsing
jjerphan Jun 30, 2026
1d82cd5
Throw `mamba_error` when a `exclude_newer` string is unparseable
jjerphan Jun 30, 2026
3406c79
Fall back on `HowardHinnant/date` for macOS
jjerphan Jul 1, 2026
e89a730
Add `howardhinnant_date` as a host dep for macOS micromamba builds
jjerphan Jul 1, 2026
71f2d5f
Require `msvcp140_atomic_wait.dll` at runtime for micromamba on Windows
jjerphan Jul 1, 2026
5e7df62
Use `howardhinnant_date-static` for macOS micromamba builds
jjerphan Jul 20, 2026
7d312bd
Add reference and remark about ISO 8601 duration format
jjerphan Jul 21, 2026
aaf90d0
Document specification of `exclude_newer_package`
jjerphan Jul 21, 2026
5cae342
Do not include user-provided values in `ExcludeNewerPolicy`
jjerphan Jul 21, 2026
6c6e8ac
Make `exclude_newer_package` part of common options
jjerphan Jul 21, 2026
e635a88
Document `howardhinnant_date` dependency
jjerphan Jul 21, 2026
951d03e
Move comment to `ExcludeNewerPolicy`'s definition
jjerphan Jul 21, 2026
7612748
Add TODO to drop Howard Hinnant date when chrono::parse is ubiquitous
jjerphan Jul 23, 2026
7ea5be7
Store exclude_newer_package as a vector of pairs
jjerphan Jul 23, 2026
67f185b
Use Markdown single backticks in exclude_newer docs
jjerphan Jul 23, 2026
b36d3ca
Drop implementation details from resolve_exclude_newer_cutoff docs
jjerphan Jul 23, 2026
b7eb3fe
Use chrono for exclude_newer reference time
jjerphan Jul 23, 2026
2bbb36e
Use fmt for exclude_newer parse error messages
jjerphan Jul 23, 2026
59094e0
Use chrono duration units for exclude_newer parsing
jjerphan Jul 23, 2026
e764579
Accumulate chrono durations in compact exclude_newer parser
jjerphan Jul 23, 2026
4424176
Adapt CMAKE_REQUIRED_FLAGS
jjerphan Jul 24, 2026
1e56c01
Fix coercion of `exclude_newer_package`
jjerphan Jul 24, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/brew.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
brew install --overwrite
fmt libarchive libsolv lz4 openssl@3 reproc simdjson xz yaml-cpp zstd
cli11 nlohmann-json spdlog tl-expected pkgconfig python msgpack
howard-hinnant-date

- name: Configure to build mamba
run: >
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/static_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,23 @@ jobs:
)
)
PY
- name: Add howardhinnant_date-static host dependency for osx
if: ${{ matrix.platform == 'osx' }}
run: |
cd micromamba-feedstock/
python3 - <<'PY'
from pathlib import Path
meta = Path("recipe/meta.yaml")
lines = meta.read_text().splitlines()
if any("howardhinnant_date-static" in line for line in lines):
raise SystemExit(0)
out = []
for line in lines:
out.append(line)
if line.strip().startswith("- lz4-c-static"):
out.append(" - howardhinnant_date-static")
meta.write_text("\n".join(out) + "\n")
PY
- name: Checkout mamba branch
uses: actions/checkout@v7
with:
Expand Down
2 changes: 2 additions & 0 deletions dev/environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ dependencies:
- spdlog >=1.16.0
- yaml-cpp >=0.8.0
- sel(win): winreg
# Replacement of `std::chrono::parse` (P0355R7) missing in libc++, see: https://github.com/llvm/llvm-project/issues/166051
- sel(osx): howardhinnant_date
# libmamba test dependencies
- catch2
# micromamba dependencies
Expand Down
2 changes: 2 additions & 0 deletions dev/environment-micromamba-static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ dependencies:
- zlib
- libnghttp2-static
- lz4-c-static
# Replacement of `std::chrono::parse` (P0355R7) missing in libc++, see: https://github.com/llvm/llvm-project/issues/166051
- sel(osx): howardhinnant_date-static
# libmamba test dependencies
- catch2
# micromamba dependencies
Expand Down
1 change: 1 addition & 0 deletions dev/micromamba_windows_allowed_dlls.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ api-ms-win-crt-string-l1-1-0.dll UCRT (ucrt) UCRT forwarder: C string and memory
api-ms-win-crt-time-l1-1-0.dll UCRT (ucrt) UCRT forwarder: time and date (time, localtime, strftime, …).
api-ms-win-crt-utility-l1-1-0.dll UCRT (ucrt) UCRT forwarder: utility routines (qsort, bsearch, system, …).
MSVCP140.dll MSVC runtime (vc14_runtime) Microsoft C++ standard library runtime (/MD builds).
msvcp140_atomic_wait.dll MSVC runtime (vc14_runtime) C++20 std::atomic wait/notify from the MSVC STL; required at runtime by std::chrono::parse (exclude_newer date/datetime parsing).
VCRUNTIME140.dll MSVC runtime (vc14_runtime) Microsoft C runtime helpers (exceptions, EH scaffolding).
VCRUNTIME140_1.dll MSVC runtime (vc14_runtime) Additional MSVC C++ exception-handling support on x64.
52 changes: 52 additions & 0 deletions libmamba/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,45 @@ cmake_policy(SET CMP0025 NEW) # Introduced in cmake 3.0
cmake_policy(SET CMP0077 NEW) # Introduced in cmake 3.13
project(libmamba)

include(CheckCXXSourceCompiles)

# std::chrono::parse (P0355) is not yet available on all platforms (e.g. libc++ on macOS).
# https://github.com/llvm/llvm-project/issues/166051
if(NOT DEFINED MAMBA_HAVE_STD_CHRONO_PARSE)
# CMAKE_REQUIRED_FLAGS is a string (not a CMake list); list(APPEND) would inject ';'.
set(CMAKE_REQUIRED_FLAGS_BACKUP "${CMAKE_REQUIRED_FLAGS}")
if(MSVC)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /std:c++20")
else()
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++20")
endif()
check_cxx_source_compiles(
"
#include <chrono>
#include <sstream>
int main()
{
std::istringstream is{ \"2020-01-01\" };
std::chrono::sys_days d{};
is >> std::chrono::parse( \"%F\", d );
return is.fail() ? 1 : 0;
}
"
MAMBA_HAVE_STD_CHRONO_PARSE
)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BACKUP}")
endif()

if(MAMBA_HAVE_STD_CHRONO_PARSE)
message(STATUS "libmamba: using std::chrono::parse for date/datetime parsing")
else()
find_package(date CONFIG REQUIRED)
message(
STATUS
"libmamba: using Howard Hinnant date for date/datetime parsing (std::chrono::parse unavailable)"
)
endif()

set(LIBMAMBA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(LIBMAMBA_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(LIBMAMBA_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
Expand Down Expand Up @@ -228,6 +267,7 @@ set(
${LIBMAMBA_SOURCE_DIR}/core/env_lockfile_mambajs.cpp
${LIBMAMBA_SOURCE_DIR}/core/environments_manager.cpp
${LIBMAMBA_SOURCE_DIR}/core/error_handling.cpp
${LIBMAMBA_SOURCE_DIR}/core/exclude_newer.cpp
${LIBMAMBA_SOURCE_DIR}/core/execution.cpp
${LIBMAMBA_SOURCE_DIR}/core/fsutil.cpp
${LIBMAMBA_SOURCE_DIR}/core/history.cpp
Expand Down Expand Up @@ -384,6 +424,7 @@ set(
${LIBMAMBA_INCLUDE_DIR}/mamba/core/env_lockfile.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/environments_manager.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/error_handling.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/exclude_newer.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/execution.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/fsutil.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/history.hpp
Expand Down Expand Up @@ -736,6 +777,11 @@ macro(libmamba_create_target target_name linkage output_name)
target_link_libraries(${target_name} PUBLIC Threads::Threads)
endif()

if(NOT MAMBA_HAVE_STD_CHRONO_PARSE)
target_compile_definitions(${target_name} PUBLIC MAMBA_USE_HOWARD_HINNANT_DATE)
target_link_libraries(${target_name} PUBLIC date::date date::date-tz)
endif()

list(APPEND libmamba_targets ${target_name})
add_library(mamba::${target_name} ALIAS ${target_name})
endmacro()
Expand Down Expand Up @@ -812,6 +858,12 @@ install(
PATTERN "*.h"
)

if(NOT MAMBA_HAVE_STD_CHRONO_PARSE)
set(LIBMAMBA_USE_HOWARD_HINNANT_DATE ON)
else()
set(LIBMAMBA_USE_HOWARD_HINNANT_DATE OFF)
endif()

# Configure 'mambaConfig.cmake' for a build tree
set(MAMBA_CONFIG_CODE "####### Expanded from \@MAMBA_CONFIG_CODE\@ #######\n")
set(
Expand Down
14 changes: 14 additions & 0 deletions libmamba/include/mamba/api/configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,20 @@ namespace mamba
node[name] = values;
}

template <>
inline void ConfigurableImpl<std::vector<std::pair<std::string, std::string>>>::dump_json(
nlohmann::json& node,
const std::string& name
) const
{
nlohmann::json object = nlohmann::json::object();
for (const auto& [key, value] : m_value)
{
object[key] = value;
}
node[name] = object;
}

template <class T>
void ConfigurableImpl<T>::set_rc_value(const T& value, const std::string& source)
{
Expand Down
71 changes: 71 additions & 0 deletions libmamba/include/mamba/api/configuration_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <optional>
#include <string>
#include <utility>
#include <vector>

#include <yaml-cpp/yaml.h>
Expand Down Expand Up @@ -170,6 +171,45 @@ namespace mamba
{
return true;
}

// Map-shaped config (e.g. exclude_newer_package): stored as vector of pairs for
// duplicate-key / order control, but configured as a YAML/JSON object — not a sequence.
// Must not use Source<vector<T>>::deserialize, which wraps the value in `[...]`.
template <>
struct Source<std::vector<std::pair<std::string, std::string>>>
{
using value_type = std::vector<std::pair<std::string, std::string>>;

static std::vector<std::string> default_value(const value_type& /* init */)
{
return { "default" };
}

static void merge(
const std::map<std::string, value_type>& values,
const std::vector<std::string>& sources,
value_type& value,
std::vector<std::string>& source
)
{
source = sources;
value = values.at(sources.front());
}

static value_type deserialize(const std::string& value)
{
if (value.empty())
{
return {};
}
return YAML::Load(value).as<value_type>();
}

static bool is_sequence()
{
return false;
}
};
}
}

Expand Down Expand Up @@ -199,6 +239,37 @@ namespace YAML
}
};

template <>
struct convert<std::vector<std::pair<std::string, std::string>>>
{
static Node encode(const std::vector<std::pair<std::string, std::string>>& rhs)
{
// Empty default Node is Null; print-config / YAML consumers need an empty Map.
Node node(NodeType::Map);
node.SetStyle(YAML::EmitterStyle::Block);
for (const auto& [key, value] : rhs)
{
node[key] = value;
}
return node;
}

static bool decode(const Node& node, std::vector<std::pair<std::string, std::string>>& rhs)
{
if (!node.IsMap())
{
return false;
}
rhs.clear();
rhs.reserve(node.size());
for (const auto& entry : node)
{
rhs.emplace_back(entry.first.as<std::string>(), entry.second.as<std::string>());
}
return true;
}
};

template <>
struct convert<mamba::VerificationLevel>
{
Expand Down
15 changes: 15 additions & 0 deletions libmamba/include/mamba/core/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <map>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "mamba/core/context_params.hpp"
Expand Down Expand Up @@ -131,6 +132,20 @@ namespace mamba
// solver options
solver::Request::Flags solver_flags = {};

/**
* Exclude packages published more recently than this duration or date.
*
* See Configurable ``exclude_newer``; resolved into ``ExcludeNewerPolicy`` at solve time.
*/
std::string exclude_newer;

/**
* Per-package overrides for ``exclude_newer`` (JSON dictionary on CLI / env vars).
*
* See Configurable ``exclude_newer_package``.
*/
std::vector<std::pair<std::string, std::string>> exclude_newer_package;

// add start menu shortcuts on Windows (not implemented on Linux / macOS)
bool shortcuts = true;

Expand Down
49 changes: 49 additions & 0 deletions libmamba/include/mamba/core/detail/chrono_parse.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2026, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.

#pragma once

#include <chrono>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>

#if defined(MAMBA_USE_HOWARD_HINNANT_DATE)
#include <date/date.h>
#include <date/tz.h>
#endif

namespace mamba::detail
{
/**
* Parse ``value`` with ``std::chrono::parse`` or ``date::from_stream`` using ``fmt``.
*
* When ``MAMBA_USE_HOWARD_HINNANT_DATE`` is set (libc++ lacks P0355;
* https://github.com/llvm/llvm-project/issues/166051), ``date::from_stream`` is used.
*
* TODO: Drop the Howard Hinnant ``date`` fallback once ``std::chrono::parse`` is
* available on all supported platforms (notably macOS/libc++).
*
* Returns ``std::nullopt`` when parsing fails or trailing characters remain.
*/
template <typename T>
[[nodiscard]] auto parse_chrono(std::string_view value, const char* fmt) -> std::optional<T>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be clear: this is necessary only because MacOS's build toolchain doesnt implement std::chrono::parse yet?
If so, could you add a TODO about this in the documentation comments to replace it when std::chrono::parse becomes available everywhere?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a TODO to drop the Howard Hinnant fallback once std::chrono::parse is ubiquitous on supported platforms.

{
std::istringstream stream{ std::string(value) };
T out{};
#if defined(MAMBA_USE_HOWARD_HINNANT_DATE)
date::from_stream(stream, fmt, out);
#else
stream >> std::chrono::parse(fmt, out);
#endif
if (stream.fail() || stream.peek() != std::istringstream::traits_type::eof())
{
return std::nullopt;
}
return out;
}
} // namespace mamba::detail
Loading
Loading