diff --git a/.gitignore b/.gitignore index eb75a0c0a5..8683115c0a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,10 @@ /documentation /etc /experimental/develop/ +/instance/ /pyvenv.cfg bin +constraints-mxdev.txt coverage/ develop-eggs downloads @@ -41,10 +43,12 @@ packages parts pip-selfcheck.json report/ +requirements-mxdev.txt src temp_resources var versions.html /venv/ +/venvs/ /share/ __pycache__ diff --git a/Makefile b/Makefile index 14d3ca1b36..280aa18811 100644 --- a/Makefile +++ b/Makefile @@ -1,42 +1,482 @@ -SHELL := /bin/bash -CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) - -# We like colors -# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects -RED=`tput setaf 1` -GREEN=`tput setaf 2` -RESET=`tput sgr0` -YELLOW=`tput setaf 3` - -all: build - -# Add the following 'help' target to your Makefile -# And add help text after each target name starting with '\#\#' -.PHONY: help -help: ## This help message - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.PHONY: all -all: build - -.PHONY: build -build: - python3 -m venv . - bin/pip install --upgrade pip - bin/pip install -r requirements.txt - bin/buildout +############################################################################## +# THIS FILE IS GENERATED BY MXMAKE +# +# DOMAINS: +#: applications.cookiecutter +#: applications.zope +#: core.base +#: core.mxenv +#: core.mxfiles +#: core.packages +#: core.sources +# +# SETTINGS (ALL CHANGES MADE BELOW SETTINGS WILL BE LOST) +############################################################################## + +## core.base + +# `deploy` target dependencies. +# No default value. +DEPLOY_TARGETS?= + +# target to be executed when calling `make run` +# No default value. +RUN_TARGET?= + +# Additional files and folders to remove when running clean target +# No default value. +CLEAN_FS?= + +# Optional makefile to include before default targets. This can +# be used to provide custom targets or hook up to existing targets. +# Default: include.mk +INCLUDE_MAKEFILE?=include.mk + +# Optional additional directories to be added to PATH in format +# `/path/to/dir/:/path/to/other/dir`. Gets inserted first, thus gets searched +# first. +# No default value. +EXTRA_PATH?= + +## core.mxenv + +# Primary Python interpreter to use. It is used to create the +# virtual environment if `VENV_ENABLED` and `VENV_CREATE` are set to `true`. +# Default: python3 +PRIMARY_PYTHON?=python3 + +# Minimum required Python version. +# Default: 3.7 +PYTHON_MIN_VERSION?=3.7 + +# Install packages using the given package installer method. +# Supported are `pip` and `uv`. If uv is used, its global availability is +# checked. Otherwise, it is installed, either in the virtual environment or +# using the `PRIMARY_PYTHON`, dependent on the `VENV_ENABLED` setting. If +# `VENV_ENABLED` and uv is selected, uv is used to create the virtual +# environment. +# Default: pip +PYTHON_PACKAGE_INSTALLER?=uv + +# Flag whether to use a global installed 'uv' or install +# it in the virtual environment. +# Default: false +MXENV_UV_GLOBAL?=false + +# Flag whether to use virtual environment. If `false`, the +# interpreter according to `PRIMARY_PYTHON` found in `PATH` is used. +# Default: true +VENV_ENABLED?=true + +# Flag whether to create a virtual environment. If set to `false` +# and `VENV_ENABLED` is `true`, `VENV_FOLDER` is expected to point to an +# existing virtual environment. +# Default: true +VENV_CREATE?=true + +# The folder of the virtual environment. +# If `VENV_ENABLED` is `true` and `VENV_CREATE` is true it is used as the +# target folder for the virtual environment. If `VENV_ENABLED` is `true` and +# `VENV_CREATE` is false it is expected to point to an existing virtual +# environment. If `VENV_ENABLED` is `false` it is ignored. +# Default: .venv +VENV_FOLDER?=.venv + +# mxdev to install in virtual environment. +# Default: mxdev +MXDEV?=mxdev + +# mxmake to install in virtual environment. +# Default: mxmake +MXMAKE?=mxmake + +## core.mxfiles + +# The config file to use. +# Default: mx.ini +PROJECT_CONFIG?=mx.ini + +## core.packages + +# Allow prerelease and development versions. +# By default, the package installer only finds stable versions. +# Default: false +PACKAGES_ALLOW_PRERELEASES?=false + +## applications.zope + +# cookiecutter configuration file to use +# Default: instance.yaml +ZOPE_CONFIGURATION_FILE?=instance.yaml + +# cookiecutter configuration file to use +# Default: https://github.com/plone/cookiecutter-zope-instance +ZOPE_TEMPLATE?=https://github.com/plone/cookiecutter-zope-instance + +# cookiecutter branch, tag or commit to checkout from the ZOPE_TEMPLATE. If empty, `--checkout` is not passed to cookiecutter. +# Default: main +ZOPE_TEMPLATE_CHECKOUT?=main + +# The Zope folder "instance" will be generated relative to this existing folder. +# Default: . +ZOPE_BASE_FOLDER?=. + +# script to run +# Default: No Default +ZOPE_SCRIPTNAME?=No Default + +############################################################################## +# END SETTINGS - DO NOT EDIT BELOW THIS LINE +############################################################################## + +INSTALL_TARGETS?= +DIRTY_TARGETS?= +CLEAN_TARGETS?= +PURGE_TARGETS?= +PRE_SOURCES_TARGETS?= + +export PATH:=$(if $(EXTRA_PATH),$(EXTRA_PATH):,)$(PATH) + +# Defensive settings for make: https://tech.davis-hansson.com/p/make/ +SHELL:=bash +.ONESHELL: +# for Makefile debugging purposes add -x to the .SHELLFLAGS +.SHELLFLAGS:=-eu -o pipefail -O inherit_errexit -c +.SILENT: +.DELETE_ON_ERROR: +MAKEFLAGS+=--warn-undefined-variables +MAKEFLAGS+=--no-builtin-rules + +# mxmake folder +MXMAKE_FOLDER?=.mxmake + +# Sentinel files +SENTINEL_FOLDER?=$(MXMAKE_FOLDER)/sentinels +SENTINEL?=$(SENTINEL_FOLDER)/about.txt +$(SENTINEL): $(firstword $(MAKEFILE_LIST)) + @mkdir -p $(SENTINEL_FOLDER) + @echo "Sentinels for the Makefile process." > $(SENTINEL) + +############################################################################## +# mxenv +############################################################################## + +# Determine the executable path +ifeq ("$(VENV_ENABLED)", "true") +export VIRTUAL_ENV=$(abspath $(VENV_FOLDER)) +ifeq ("$(OS)", "Windows_NT") +VENV_EXECUTABLE_FOLDER=$(VIRTUAL_ENV)/Scripts +else +VENV_EXECUTABLE_FOLDER=$(VIRTUAL_ENV)/bin +endif +export PATH:=$(VENV_EXECUTABLE_FOLDER):$(PATH) +MXENV_PYTHON=python +else +MXENV_PYTHON=$(PRIMARY_PYTHON) +endif + +# Determine the package installer +ifeq ("$(PYTHON_PACKAGE_INSTALLER)","uv") +PYTHON_PACKAGE_COMMAND=uv pip +else +PYTHON_PACKAGE_COMMAND=$(MXENV_PYTHON) -m pip +endif + +MXENV_TARGET:=$(SENTINEL_FOLDER)/mxenv.sentinel +$(MXENV_TARGET): $(SENTINEL) + @$(PRIMARY_PYTHON) -c "import sys; vi = sys.version_info; sys.exit(1 if (int(vi[0]), int(vi[1])) >= tuple(map(int, '$(PYTHON_MIN_VERSION)'.split('.'))) else 0)" \ + && echo "Need Python >= $(PYTHON_MIN_VERSION)" && exit 1 || : + @[[ "$(VENV_ENABLED)" == "true" && "$(VENV_FOLDER)" == "" ]] \ + && echo "VENV_FOLDER must be configured if VENV_ENABLED is true" && exit 1 || : + @[[ "$(VENV_ENABLED)$(PYTHON_PACKAGE_INSTALLER)" == "falseuv" ]] \ + && echo "Package installer uv does not work with a global Python interpreter." && exit 1 || : +ifeq ("$(VENV_ENABLED)", "true") +ifeq ("$(VENV_CREATE)", "true") +ifeq ("$(PYTHON_PACKAGE_INSTALLER)$(MXENV_UV_GLOBAL)","uvtrue") + @echo "Setup Python Virtual Environment using package 'uv' at '$(VENV_FOLDER)'" + @uv venv -p $(PRIMARY_PYTHON) --seed $(VENV_FOLDER) +else + @echo "Setup Python Virtual Environment using module 'venv' at '$(VENV_FOLDER)'" + @$(PRIMARY_PYTHON) -m venv $(VENV_FOLDER) + @$(MXENV_PYTHON) -m ensurepip -U +endif +endif +else + @echo "Using system Python interpreter" +endif +ifeq ("$(PYTHON_PACKAGE_INSTALLER)$(MXENV_UV_GLOBAL)","uvfalse") + @echo "Install uv" + @$(MXENV_PYTHON) -m pip install uv +endif + @$(PYTHON_PACKAGE_COMMAND) install -U pip setuptools wheel + @echo "Install/Update MXStack Python packages" + @$(PYTHON_PACKAGE_COMMAND) install -U $(MXDEV) $(MXMAKE) + @touch $(MXENV_TARGET) + +.PHONY: mxenv +mxenv: $(MXENV_TARGET) + +.PHONY: mxenv-dirty +mxenv-dirty: + @rm -f $(MXENV_TARGET) + +.PHONY: mxenv-clean +mxenv-clean: mxenv-dirty +ifeq ("$(VENV_ENABLED)", "true") +ifeq ("$(VENV_CREATE)", "true") + @rm -rf $(VENV_FOLDER) +endif +else + @$(PYTHON_PACKAGE_COMMAND) uninstall -y $(MXDEV) + @$(PYTHON_PACKAGE_COMMAND) uninstall -y $(MXMAKE) +endif + +INSTALL_TARGETS+=mxenv +DIRTY_TARGETS+=mxenv-dirty +CLEAN_TARGETS+=mxenv-clean + +############################################################################## +# sources +############################################################################## + +SOURCES_TARGET:=$(SENTINEL_FOLDER)/sources.sentinel + +# pre sources targets to be used in includes +#PRE_SOURCES_TARGETS?= +$(SOURCES_TARGET): $(PROJECT_CONFIG) $(MXENV_TARGET) $(PRE_SOURCES_TARGETS) + @echo "Checkout project sources" + @mxdev -o -c $(PROJECT_CONFIG) + @touch $(SOURCES_TARGET) + +.PHONY: sources +sources: $(SOURCES_TARGET) + +.PHONY: sources-dirty +sources-dirty: + @rm -f $(SOURCES_TARGET) + +.PHONY: sources-purge +sources-purge: sources-dirty + @rm -rf sources + +INSTALL_TARGETS+=sources +DIRTY_TARGETS+=sources-dirty +PURGE_TARGETS+=sources-purge + +############################################################################## +# mxfiles +############################################################################## + +# case `core.sources` domain not included +SOURCES_TARGET?= + +# File generation target +MXMAKE_FILES?=$(MXMAKE_FOLDER)/files + +# set environment variables for mxmake +define set_mxfiles_env + @export MXMAKE_FILES=$(1) +endef + +# unset environment variables for mxmake +define unset_mxfiles_env + @unset MXMAKE_FILES +endef + +$(PROJECT_CONFIG): +ifneq ("$(wildcard $(PROJECT_CONFIG))","") + @touch $(PROJECT_CONFIG) +else + @echo "[settings]" > $(PROJECT_CONFIG) +endif + +LOCAL_PACKAGE_FILES:=$(wildcard pyproject.toml setup.cfg setup.py requirements.txt constraints.txt) + +FILES_TARGET:=requirements-mxdev.txt +$(FILES_TARGET): $(PROJECT_CONFIG) $(MXENV_TARGET) $(SOURCES_TARGET) $(LOCAL_PACKAGE_FILES) + @echo "Create project files" + @mkdir -p $(MXMAKE_FILES) + $(call set_mxfiles_env,$(MXMAKE_FILES)) + @mxdev -n -c $(PROJECT_CONFIG) + $(call unset_mxfiles_env) + @test -e $(MXMAKE_FILES)/pip.conf && cp $(MXMAKE_FILES)/pip.conf $(VENV_FOLDER)/pip.conf || : + @touch $(FILES_TARGET) + +.PHONY: mxfiles +mxfiles: $(FILES_TARGET) + +.PHONY: mxfiles-dirty +mxfiles-dirty: + @touch $(PROJECT_CONFIG) + +.PHONY: mxfiles-clean +mxfiles-clean: mxfiles-dirty + @rm -rf constraints-mxdev.txt requirements-mxdev.txt $(MXMAKE_FILES) + +INSTALL_TARGETS+=mxfiles +DIRTY_TARGETS+=mxfiles-dirty +CLEAN_TARGETS+=mxfiles-clean + +############################################################################## +# packages +############################################################################## + +# additional sources targets which requires package re-install on change +-include $(MXMAKE_FILES)/additional_sources_targets.mk +ADDITIONAL_SOURCES_TARGETS?= + +INSTALLED_PACKAGES=$(MXMAKE_FILES)/installed.txt + +ifeq ("$(PACKAGES_ALLOW_PRERELEASES)","true") +ifeq ("$(PYTHON_PACKAGE_INSTALLER)","uv") +PACKAGES_PRERELEASES=--prerelease=allow +else +PACKAGES_PRERELEASES=--pre +endif +else +PACKAGES_PRERELEASES= +endif + +PACKAGES_TARGET:=$(INSTALLED_PACKAGES) +$(PACKAGES_TARGET): $(FILES_TARGET) $(ADDITIONAL_SOURCES_TARGETS) + @echo "Install python packages" + @$(PYTHON_PACKAGE_COMMAND) install $(PACKAGES_PRERELEASES) -r $(FILES_TARGET) + @$(PYTHON_PACKAGE_COMMAND) freeze > $(INSTALLED_PACKAGES) + @touch $(PACKAGES_TARGET) + +.PHONY: packages +packages: $(PACKAGES_TARGET) + +.PHONY: packages-dirty +packages-dirty: + @rm -f $(PACKAGES_TARGET) + +.PHONY: packages-clean +packages-clean: + @test -e $(FILES_TARGET) \ + && test -e $(MXENV_PYTHON) \ + && $(MXENV_PYTHON) -m pip uninstall -y -r $(FILES_TARGET) \ + || : + @rm -f $(PACKAGES_TARGET) + +INSTALL_TARGETS+=packages +DIRTY_TARGETS+=packages-dirty +CLEAN_TARGETS+=packages-clean + +############################################################################## +# cookiecutter +############################################################################## + +COOKIECUTTER_TARGET:=$(SENTINEL_FOLDER)/cookiecutter.sentinel +$(COOKIECUTTER_TARGET): $(MXENV_TARGET) + @echo "Install cookiecutter" + @$(PYTHON_PACKAGE_COMMAND) install "cookiecutter>=2.6.0" + @touch $(COOKIECUTTER_TARGET) + +.PHONY: cookiecutter +cookiecutter: $(COOKIECUTTER_TARGET) + +.PHONY: cookiecutter-dirty +cookiecutter-dirty: + @rm -f $(COOKIECUTTER_TARGET) + +.PHONY: cookiecutter-clean +cookiecutter-clean: cookiecutter-dirty + @test -e $(MXENV_PYTHON) && $(MXENV_PYTHON) -m pip uninstall -y cookiecutter || : + @rm -f $(COOKIECUTTER_TARGET) + +DIRTY_TARGETS+=cookiecutter-dirty +CLEAN_TARGETS+=cookiecutter-clean + +############################################################################## +# zope +############################################################################## + +ZOPE_INSTANCE_FOLDER:=$(ZOPE_BASE_FOLDER)/instance +ZOPE_INSTANCE_TARGET:=$(ZOPE_INSTANCE_FOLDER)/etc/zope.ini $(ZOPE_INSTANCE_FOLDER)/etc/zope.conf $(ZOPE_INSTANCE_FOLDER)/etc/site.zcml + +ifeq (,$(ZOPE_TEMPLATE_CHECKOUT)) + ZOPE_COOKIECUTTER_TEMPLATE_OPTIONS= +else + ZOPE_COOKIECUTTER_TEMPLATE_OPTIONS=--checkout $(ZOPE_TEMPLATE_CHECKOUT) +endif + +${ZOPE_CONFIGURATION_FILE}: + @touch ${ZOPE_CONFIGURATION_FILE} + +$(ZOPE_INSTANCE_TARGET): $(COOKIECUTTER_TARGET) $(ZOPE_CONFIGURATION_FILE) + @echo Create Plone/Zope configuration from $(ZOPE_TEMPLATE) to $(ZOPE_INSTANCE_FOLDER) + @cookiecutter -f --no-input ${ZOPE_COOKIECUTTER_TEMPLATE_OPTIONS} --config-file $(ZOPE_CONFIGURATION_FILE) --output-dir $(ZOPE_BASE_FOLDER) $(ZOPE_TEMPLATE) + +.PHONY: zope-instance +zope-instance: $(ZOPE_INSTANCE_TARGET) $(SOURCES) + +.PHONY: zope-start +zope-start: $(ZOPE_INSTANCE_TARGET) $(PACKAGES_TARGET) + @echo "Start Zope/Plone with configuration in $(ZOPE_INSTANCE_FOLDER)" + @runwsgi -v "$(ZOPE_INSTANCE_FOLDER)/etc/zope.ini" + +.PHONY: zope-debug +zope-debug: $(ZOPE_INSTANCE_TARGET) $(PACKAGES_TARGET) + @echo "Start Zope/Plone with configuration in $(ZOPE_INSTANCE_FOLDER)" + @zconsole debug "$(ZOPE_INSTANCE_FOLDER)/etc/zope.ini" + +.PHONY: zope-runscript +zope-runscript: $(ZOPE_INSTANCE_TARGET) $(PACKAGES_TARGET) + @echo "Run Zope/Plone Console Script $(ZOPE_SCRIPTNAME) in $(ZOPE_INSTANCE_FOLDER)" + @zconsole run "$(ZOPE_INSTANCE_FOLDER)/etc/zope.ini" $(ZOPE_SCRIPTNAME) + +.PHONY: zope-dirty +zope-dirty: + @touch ${ZOPE_CONFIGURATION_FILE} + +.PHONY: zope-clean +zope-clean: + @touch ${ZOPE_CONFIGURATION_FILE} + @rm -rf $(ZOPE_INSTANCE_FOLDER)/etc $(ZOPE_INSTANCE_FOLDER)/inituser + +.PHONY: zope-purge +zope-purge: zope-dirty + @rm -rf $(ZOPE_INSTANCE_FOLDER) + +INSTALL_TARGETS+=zope-instance +DIRTY_TARGETS+=zope-dirty +CLEAN_TARGETS+=zope-clean + +-include $(INCLUDE_MAKEFILE) + +############################################################################## +# Default targets +############################################################################## + +INSTALL_TARGET:=$(SENTINEL_FOLDER)/install.sentinel +$(INSTALL_TARGET): $(INSTALL_TARGETS) + @touch $(INSTALL_TARGET) + +.PHONY: install +install: $(INSTALL_TARGET) + @touch $(INSTALL_TARGET) + +.PHONY: run +run: $(RUN_TARGET) + +.PHONY: deploy +deploy: $(DEPLOY_TARGETS) + +.PHONY: dirty +dirty: $(DIRTY_TARGETS) + @rm -f $(INSTALL_TARGET) .PHONY: clean -clean: ## Remove old virtualenv and creates a new one - @echo "Clean" - rm -rf develop-eggs eggs bin lib include share .Python .installed.cfg .mr.developer.cfg - -.PHONY: test -test: ## Run tests - @echo "$(GREEN)==> Run Tests$(RESET)" - bin/test --xml - -.PHONY: test-acceptance -test-acceptance: ## Run acceptance tests - @echo "$(GREEN)==> Run Acceptance Tests$(RESET)" - export ROBOTSUITE_PREFIX=ONLYROBOT && bin/alltests -t ONLYROBOT --all --xml +clean: dirty $(CLEAN_TARGETS) + @rm -rf $(CLEAN_TARGETS) $(MXMAKE_FOLDER) $(CLEAN_FS) + +.PHONY: purge +purge: clean $(PURGE_TARGETS) + +.PHONY: runtime-clean +runtime-clean: + @echo "Remove runtime artifacts, like byte-code and caches." + @find . -name '*.py[c|o]' -delete + @find . -name '*~' -exec rm -f {} + + @find . -name '__pycache__' -exec rm -fr {} + diff --git a/README-make.md b/README-make.md new file mode 100644 index 0000000000..a2e0c5f1b8 --- /dev/null +++ b/README-make.md @@ -0,0 +1,131 @@ +# Using the Makefile in buildout.coredev + +Traditionally, the way to run `buildout.coredev`, was to use Buildout, and you can still do that. +Basically: + +``` +python -mvenv . +bin/pip install -r requirements.txt +bin/buildout +``` + +Buildout is not well known outside of the Plone world, and it can have problems when a new `pip` or `setuptools` version is released. +So we are busy putting pip on the same level as Buildout for doing core development. +See [CMFPlone issue 3670](https://github.com/plone/Products.CMFPlone/issues/3670). + +This document describes the current status, and mostly how you use the included `Makefile`. +This is work in progress. Once things have settled over the coming months, we can put this in the main documentation. + +Remember: for now you can still choose to ignore this and continue to use Buildout for core Plone development. + + +## Goal + +The goal of the `Makefile` is to offer a pip-based alternative for what Buildout has offered so far. +Those are: + +* Define which versions of Python packages to use. +* Define for which packages we should ignore the version pin and use a checkout instead, using the `mr.developer` Buildout extension. +* Create a Plone instance based on some configuration. +* Create a script for starting Plone: `bin/instance fg` +* Create a script for running tests of core Plone packages: `bin/test` or `bin/test -s package.name` + + +## Tools + +First, there are some tools you should know about. + + +### `plone.releaser` + +[`plone.releaser`](https://github.com/plone/plone.releaser) is our wrapper around [`zest.releaser`](https://github.com/zestsoftware/zest.releaser), used for releasing Pythong packages. +But it also introduces a `manage` script that has recently gotten some extra commands. +These are needed to translate between our current Buildout files and what we need for `pip`. + +* `manage versions2constraints` takes the `versions*.cfg` files and translates them to `constraints*.txt` files for use by `pip`. +* `manage buildout2pip` does the same, but also translates `sources.cfg` and `checkouts.cfg` (used by `mr.developer`) to `mxsources.ini` and `mxcheckouts.ini` (for use by `mxdev`). + +In the future there should be commands that do the opposite, so we can start treating the `pip/mxdev` files as canonical, and generate their Buildout counterparts for those still using Buildout. + + +### mxdev + +`mxdev` is used instead of the `mr.developer` Buildout extension. +Its goal is to take requirements and constraints, and ignore some of the constraints to replace them with source checkouts. +The end result are some files that `pip` (or `uv`) then uses to install Python packages. + +See https://github.com/mxstack/mxdev/tree/main + + +### mxmake + +`mxmake` was used to generate the `Makefile`. +This means you should not edit the `Makefile` by hand. +Please only touch `include.mk` if anything needs to be changed or extra targets are needed. + +Every now and then we can regenerate the `Makefile`. +TODO: how do we do that? + +See https://mxstack.github.io/mxmake + + +## How to use the `Makefile` + +At the top of the `Makefile` you see several domains or topics that are included. +These [topics are documented](https://mxstack.github.io/mxmake/topics.html). +So if you want details about `make` targets, you can look there. +Here, let me introduce the main ones. + + +### Install + +`make install` calls several other `make` targets, listed in `INSTALL_TARGETS`. +If you `grep INSTALL_TARGETS Makefile include.mk` you can see which they are. +Currently: + +* mxenv +* sources +* mxfiles +* packages +* zope-instance +* PLONERELEASER_TARGET, which installs `plone.releaser` + +You can call those targets individually as well, if you know you want to run a specific one. + +Main results: + +* In the `src` directory there are checkouts of packages, just like `mr.developer` would do. + You can still use Buildout and `mr.developer` next to this: the two approaches can work side by side. +* In `.venv` there is a virtual environment with Plone and all test requirements installed. +* In `instance` a Zope instance is created. + + +### Start + +Run `make zope-start` to start the Zope instance. + + +### Run tests + +This is not in the Makefile yet. We need to figure out how best to run the tests first. +A few sample commands that work for me: + +``` +.venv/bin/zope-testrunner --test-path src/Products.CMFPlone -u +.venv/bin/zope-testrunner --test-path .venv/lib/python3.12/site-packages -s plone.memoize +``` + + +### Dirty and clean + +Most targets have two related targets, for "dirty" and "clean". +What do these do? +Let's give an example. + +* `make mxfiles` creates `constraints-mxdev.txt requirements-mxdev.txt` +* Run `make mxfiles` again, and nothing happens, because everything is up to date. +* `make mxfiles-dirty` signals to make that the `mxfiles` target is "dirty". +* This means that the next run of `make mxfiles` will create the files again. +* You can also call `make mxfiles-clean. + This has the same effect as `make mxfiles-dirty`, but it also cleans: + it removes the files that were created by the previous `make mxfiles` call. diff --git a/constraints-all.txt b/constraints-all.txt new file mode 100644 index 0000000000..20e3bac19b --- /dev/null +++ b/constraints-all.txt @@ -0,0 +1,4 @@ +# At some point we will want only one constraints file, without extends. +-c constraints.txt +-c constraints-extra.txt +-c constraints-ecosystem.txt diff --git a/include.mk b/include.mk new file mode 100644 index 0000000000..8b8236f86e --- /dev/null +++ b/include.mk @@ -0,0 +1,45 @@ +PYTHON_MIN_VERSION=3.10 + +# Plone releaser +PLONERELEASER_TARGET:=$(SENTINEL_FOLDER)/plonereleaser.sentinel +$(PLONERELEASER_TARGET): $(MXENV_TARGET) + @echo "Install plone.releaser" + @$(PYTHON_PACKAGE_COMMAND) install plone.releaser +# @$(PYTHON_PACKAGE_COMMAND) install git+https://github.com/plone/plone.releaser.git@master#plone.releaser + @touch $(PLONERELEASER_TARGET) + +.PHONY: plonereleaser-dirty +plonereleaser-dirty: + @rm -f $(PLONERELEASER_TARGET) + +.PHONY: plonereleaser-clean +plonereleaser-clean: plonereleaser-dirty + @test -e $(MXENV_PYTHON) && $(MXENV_PYTHON) -m pip uninstall -y plone.releaser || : + +INSTALL_TARGETS+=$(PLONERELEASER_TARGET) +CHECK_TARGETS+=plonereleaser-check +FORMAT_TARGETS+=plonereleaser-format +DIRTY_TARGETS+=plonereleaser-dirty +CLEAN_TARGETS+=plonereleaser-clean + +# versions2constraints +VERSIONS2CONSTRAINTS_TARGET:=constraints.txt constraints-ecosystem.txt constraints-extra.txt +$(VERSIONS2CONSTRAINTS_TARGET): $(PLONERELEASER_TARGET) versions.cfg versions-ecosystem.cfg versions-extra.cfg + @echo "Generate pip constraints from buildout" + @manage versions2constraints + + +# buildout2pip +BUILDOUT2PIP_TARGET:=mxsources.ini mxcheckouts.ini +$(BUILDOUT2PIP_TARGET): $(PLONERELEASER_TARGET) checkouts.cfg sources.cfg + @echo "Generate mx sources and checkouts from buildout" + @manage buildout2pip + + +# configure to run pre sources +PRE_SOURCES_TARGETS+=$(BUILDOUT2PIP_TARGET) $(VERSIONS2CONSTRAINTS_TARGET) + +.PHONY: run-presources +run-presources: $(PRE_SOURCES_TARGETS) + @echo "Manual run pre sources targets" + diff --git a/instance.yaml b/instance.yaml new file mode 100644 index 0000000000..e4eff13979 --- /dev/null +++ b/instance.yaml @@ -0,0 +1,33 @@ +--- +# This is a cookiecutter configuration context file for +# +# cookiecutter-zope-instance +# +# available options are documented at +# https://github.com/bluedynamics/cookiecutter-zope-instance/ +# +# read also README_MAKE.md in this folder +# +default_context: + initial_user_password: admin + debug_mode: on +# When we have installed a PyPI release of Products.CMFPlone, it ends up in +# .venv/lib/python3.12/site-packages/Products which means that all its zcml +# gets read automatically and its initialize function gets called. This is +# handled by OFS.Application. All is well. +# +# When we use a src checkout of Products.CMFPlone, this is not true. +# So we must explicitly load all its zcml. +# And separately we must add five:registerPackage to its configure.zcml, +# otherwise its initialize function is not called. +# Sample errors you can get when this is not done right: +# +# * ConfigurationError: ('Unknown directive', 'http://namespaces.zope.org/zope', 'autoIncludePluginsOverrides') +# * ConfigurationError: ('Unknown directive', 'http://namespaces.plone.org/plone', 'portlet') +# * KeyError: 'Unicode Whitespace splitter' (when creating a Plone Site) +# +# Note that once its zcml is loaded, CMFPlone uses plone/z3c.autoinclude, +# so for packages that use this, no explicit handling is needed here. + zcml_package_metas: ['Products.CMFPlone'] + zcml_package_includes: ['Products.CMFPlone'] + zcml_package_overrides: ['Products.CMFPlone'] diff --git a/mx.ini b/mx.ini new file mode 100644 index 0000000000..4c278d0428 --- /dev/null +++ b/mx.ini @@ -0,0 +1,17 @@ +[settings] +threads = 5 + +# With an empty 'requirements-in' mxdev only generates a list of checkouts: +# '-e src/Plone', etc. That can be nice. +# General problem though: if you have '-e src/Plone' in the requirements-out, +# then all dependencies of the Plone will get installed, even if you would +# only want Products.CMFPlone and its dependencies. We may tackle this later. +# For now, let's basically require everything we could ever want, +# especially all test dependencies. +requirements-in = requirements-test.txt +requirements-out = requirements-mxdev.txt +default-target = src +include = + mxsources.ini + mxcheckouts.ini + mxtests.ini diff --git a/mxcheckouts.ini b/mxcheckouts.ini index 6be8e2daf4..57738d8b52 100644 --- a/mxcheckouts.ini +++ b/mxcheckouts.ini @@ -21,9 +21,3 @@ use = true [plone.restapi] use = true - -[Products.isurlinportal] -use = true - -[plone.app.contentmenu] -use = true diff --git a/mxtests.ini b/mxtests.ini new file mode 100644 index 0000000000..8d4015cb49 --- /dev/null +++ b/mxtests.ini @@ -0,0 +1,125 @@ +# If mxcheckouts.txt says we want to use plone.volto, then the generated +# requirements-mxdev.txt will have this line: +# plone.volto [test] -> mxdev disabled (source) +# This would mean the 'test' extra of plone.volto will not get installed. +# So we need to define the extras that we want in case of a checkout. + +[diazo] +extras = test + +[plone.api] +extras = test + +[plone.app.caching] +extras = test + +[plone.app.contentlisting] +extras = test + +[plone.app.contenttypes] +extras = test + +[plone.app.discussion] +extras = test + +[plone.app.event] +extras = test + +[plone.app.iterate] +extras = test + +[plone.app.layout] +extras = test + +[plone.app.linkintegrity] +extras = test + +[plone.app.portlets] +extras = test + +[# plone.app.robotframework] +extras = test + +[plone.app.testing] +extras = test + +[plone.app.textfield] +extras = tests + +[plone.app.theming] +extras = test + +[plone.app.upgrade] +extras = test + +[plone.app.users] +extras = test + +[plone.app.versioningbehavior] +extras = tests + +[plone.app.widgets] +extras = test + +[plone.app.z3cform] +extras = test + +[plone.cachepurging] +extras = test + +[plone.dexterity] +extras = test + +[plone.event] +extras = test + +[plone.namedfile] +extras = test + +[plone.outputfilters] +extras = test + +[plone.resource] +extras = test + +[plone.resourceeditor] +extras = test + +[plone.rest] +extras = test + +[plone.restapi] +extras = test + +[plone.schemaeditor] +extras = test + +[plone.subrequest] +extras = test + +[plone.supermodel] +extras = test + +[plone.testing] +extras = test + +[plone.transformchain] +extras = test + +[plone.uuid] +extras = test + +[plone.volto] +extras = test + +[plone.z3cform] +extras = test + +[Products.CMFPlacefulWorkflow] +extras = test + +[Products.CMFPlone] +extras = test + +[Products.DateRecurringIndex] +extras = test diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000000..75f1e16b40 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,109 @@ +# Copied from tests.cfg +-c constraints-all.txt +borg.localrole +collective.monkeypatcher +diazo [test] +five.customerize +five.intid +plone.alterego +plone.api [test] +plone.app.caching [test] +plone.app.content +plone.app.contentlisting [test] +plone.app.contentmenu +plone.app.contentrules +plone.app.contenttypes [test] +plone.app.customerize +plone.app.dexterity +plone.app.discussion [test] +plone.app.event [test] +plone.app.i18n +plone.app.intid +plone.app.iterate [test] +plone.app.layout [test] +plone.app.linkintegrity [test] +plone.app.locales +plone.app.lockingbehavior +plone.app.multilingual +plone.app.portlets [test] +plone.app.querystring +plone.app.redirector +plone.app.registry +plone.app.relationfield +# plone.app.robotframework [test] +plone.app.testing [test] +plone.app.textfield [tests] +plone.app.theming [test] +plone.app.upgrade [test] +plone.app.users [test] +plone.app.uuid +plone.app.versioningbehavior [tests] +plone.app.viewletmanager +plone.app.vocabularies +plone.app.widgets [test] +plone.app.workflow +plone.app.z3cform [test] +plone.autoform +plone.batching +plone.behavior +plone.base +plone.browserlayer +plone.cachepurging [test] +plone.caching +plone.contentrules +plone.dexterity [test] +plone.event [test] +plone.folder +plone.formwidget.namedfile +plone.i18n +plone.indexer +plone.intelligenttext +plone.keyring +plone.locking +plone.memoize +plone.namedfile [test] +plone.outputfilters [test] +plone.portlet.collection +plone.portlet.static +plone.portlets +plone.protect +plone.registry +plone.resource [test] +plone.resourceeditor [test] +plone.rest [test] +plone.restapi [test] +plone.rfc822 +plone.scale +plone.schema +plone.schemaeditor [test] +plone.session +plone.staticresources +plone.stringinterp +plone.subrequest [test] +plone.supermodel [test] +plone.testing [test] +plone.theme +plone.transformchain [test] +plone.uuid [test] +plone.volto [test] +plone.z3cform [test] +plonetheme.barceloneta +Products.CMFDiffTool +Products.CMFDynamicViewFTI +Products.CMFEditions +Products.CMFPlacefulWorkflow [test] +Products.CMFPlone [test] +Products.CMFUid +Products.DateRecurringIndex [test] +Products.DCWorkflow +Products.ExtendedPathIndex +Products.GenericSetup +Products.isurlinportal +Products.MimetypesRegistry +Products.PlonePAS +Products.PluggableAuthService +Products.PluginRegistry +Products.PortalTransforms +Products.statusmessages +Products.ZopeVersionControl +repoze.xmliter