feat: nix support

- Provide a dev shell.
- Provide a nix package.
- Provide a nix flake.
- Development environment based on direnv.
- Docs.
- Configure Gitpod to use direnv and nix.
- Configure Cachix out of the box, and document how to use it.
- Add direnv and nix to CI.
- Satisfy some linters that came from Precommix, even when Precommix was later discarded.
- Mark some tests as impure.
- Run only pure tests when building Copier with Nix.
- Add poetry loader to direnv.
- Update contribution guide.
This commit is contained in:
Jairo Llopis 2023-01-18 09:40:08 +00:00 committed by GitHub
parent dae31980a3
commit 67cc4ffde3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1254 additions and 953 deletions

View File

@ -1,12 +1,16 @@
# Defaults for all kinds of source code
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
root = true
# Specific language overrides
[*.{yml,yaml,json}]
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.py]
# For isort
profile = black
[*.{code-snippets,code-workspace,json,lock,nix,tf,yaml,yml}{,.jinja}]
indent_size = 2

19
.envrc Normal file
View File

@ -0,0 +1,19 @@
# SEE https://github.com/direnv/direnv/wiki/Python#poetry
layout_poetry() {
VIRTUAL_ENV=$(poetry env info --path 2>/dev/null ; true)
if [[ -z $VIRTUAL_ENV || ! -d $VIRTUAL_ENV ]]; then
log_status "No virtual environment exists. Executing \`poetry install\` to create one."
poetry install --with dev,docs
VIRTUAL_ENV=$(poetry env info --path)
fi
PATH_add "$VIRTUAL_ENV/bin"
export POETRY_ACTIVE=1
export VIRTUAL_ENV
}
use flake . \
--extra-substituters 'https://copier.cachix.org https://devenv.cachix.org' \
--extra-trusted-public-keys 'copier.cachix.org-1:sVkdQyyNXrgc53qXPCH9zuS91zpt5eBYcg7JQSmTBG4= devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw='
layout_poetry

View File

@ -1,4 +1,6 @@
[flake8]
extend-ignore = W503,E203,E501,D100,D101,D102,D103,D104,D105,D107,SIM117
max-complexity = 20
ignore = E203, E501, W503, B950
max-line-length = 88
select = C,E,F,W,B
per-file-ignores=
__init__.py:F401

View File

@ -68,7 +68,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install poetry poetry-dynamic-versioning
poetry install --with docs -v
poetry install --with dev,docs -v
- name: Run pytest
run: poetry run poe test --cov=./ --cov-report=xml -ra .
- name: Upload coverage to Codecov
@ -84,9 +84,55 @@ jobs:
name: copier
token: ${{ secrets.CODECOV_TOKEN }}
flake-check:
strategy:
fail-fast: false
matrix:
os:
- macos-latest
- ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
# Install Nix and set up Cachix
- uses: cachix/install-nix-action@v17
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v11
with:
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
extraPullNames: devenv
name: copier
pushFilter: (-source$|nixpkgs\.tar\.gz$)
# Cache for poetry venv when using direnv
- uses: actions/cache@v3
with:
path: |
.cache
.devenv
.direnv
.venv
key:
direnv|${{ runner.os }}|${{ hashFiles('pyproject.toml', '*.lock', '*.nix')
}}
# Check direnv works as expected
- uses: JRMurr/direnv-nix-action@v2
with:
install-nix: "false"
cache-store: "false"
- run: copier --version
# Run nix checks
- run: nix flake check -L
publish:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
needs: build
needs:
- build
- flake-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

6
.gitignore vendored
View File

@ -58,3 +58,9 @@ htmlcov/
# macOS
.DS_Store
# Nix
/.devenv
/.direnv
/.pre-commit-config.yaml
/result*

View File

@ -1,8 +0,0 @@
FROM gitpod/workspace-full
USER gitpod
ENV PIP_USER=no POETRY_VIRTUALENVS_IN_PROJECT=true
RUN pip3 install \
commitizen \
poethepoet \
poetry \
poetry-dynamic-versioning

View File

@ -1,3 +1,10 @@
github:
prebuilds:
addBadge: true
addCheck: prevent-merge-on-error
master: true
pullRequests: true
vscode:
extensions:
- bpruitt-goddard.mermaid-markdown-syntax-highlighting
@ -5,15 +12,10 @@ vscode:
- esbenp.prettier-vscode
- ms-python.python
image:
file: .gitpod.dockerfile
ports:
# Mkdocs local server; start it with `poe docs`
- port: 8000
onOpen: notify
tasks:
- init:
export PIP_USER=no && poetry install -E docs && poetry run pre-commit install -t
pre-commit -t commit-msg && poetry run pre-commit install-hooks
- init: direnv allow

View File

@ -1,99 +0,0 @@
default_language_version:
python: python3
default_stages:
- commit
repos:
# checking our hooks themselves
- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
# hooks running from local virtual environment
- repo: local
hooks:
- id: autoflake
name: autoflake
entry: poetry run autoflake
language: system
types: [python]
args: ["-i", "--remove-all-unused-imports", "--ignore-init-module-imports"]
- id: black
name: black
entry: poetry run black
language: system
types: [python]
require_serial: true
- id: flake8
name: flake8
entry: poetry run flake8
language: system
types: [python]
require_serial: true
- id: poetry_check
description: Check the integrity of pyproject.toml
name: poetry_check
entry: poetry check
language: system
pass_filenames: false
require_serial: true
- id: poetry-lock-check
name: poetry-lock-check
entry: poetry lock
args: ["--check"]
language: system
pass_filenames: false
- id: isort
name: isort
entry: poetry run isort
require_serial: true
language: system
types_or: [cython, pyi, python]
args: ["--filter-files"]
- id: commitizen
name: commitizen
entry: poetry run cz check
args: [--allow-abort, --commit-msg-file]
language: system
stages: [commit-msg]
- repo: https://github.com/asottile/pyupgrade
rev: v3.2.1
hooks:
- id: pyupgrade
args: [--py37-plus]
# prettier to format our many yaml files
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
exclude: |
(?x)
# Those files have wrong syntax and would fail
^tests/demo_invalid/copier.yml|tests/demo_transclude_invalid(_multi)?/demo/copier.yml$
# HACK https://github.com/prettier/prettier/issues/9430
|^tests/demo
# miscellaneous hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-added-large-files
- id: check-ast
- id: check-case-conflict
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-toml
- id: debug-statements
- id: detect-private-key
- id: end-of-file-fixer
exclude: \.noeof\. # Some tests require no EOF
- id: fix-encoding-pragma
args: ["--remove"]
- id: mixed-line-ending
args: ["--fix=lf"]
- id: trailing-whitespace

View File

@ -1,5 +1,2 @@
# Defaults for all prettier-supported languages
bracketSpacing: false
endOfLine: lf
printWidth: 88
proseWrap: always

View File

@ -47,14 +47,21 @@ Feel free to discuss with our community through
## Dev Environment Setup
The recommended way is:
1. Click on
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/copier-org/copier)
1. Wait until the terminal that pops up is ready.
1. Accept the direnv and nix pop-ups that appear.
For local or more complex setups, continue reading.
We use some tools as part of our development workflow which you'll need to install into
your host environment:
- [Poetry](https://python-poetry.org/) v1.2+ for packaging and dependency management
Or you can use
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/copier-org/copier)
to start hacking with one click!
- [Nix](https://nixos.org/download.html) to provide a reproducible development
environment.
- [Direnv](https://direnv.net/) to load that environment automatically in your shell.
## Get Started!
@ -68,22 +75,18 @@ Ready to contribute? Here's how to set up the project for local development.
cd copier
```
1. Use Poetry to set up a development environment:
1. Use Direnv to set up a development environment:
```shell
# Tell Poetry to create the virtualenv in the project directory
poetry config virtualenvs.in-project true --local
# Create a virtualenv with all dependencies from pyproject.toml
poetry install --with docs
# Install development helper tools
poetry run pre-commit install -t pre-commit -t commit-msg
# Create a new shell with the virtualenv activated
poetry shell
# Let direnv do its magic
direnv allow
```
Direnv will take some time to load for the 1st time. It will download all
development dependencies, including [Poetry](https://python-poetry.org/), and it
will use it to create a virtualenv and install Copier with all its development
dependencies too.
1. Create a branch for local development:
```shell
@ -99,9 +102,6 @@ Ready to contribute? Here's how to set up the project for local development.
poe lint
```
To have multiple Python versions on the same machine for running `tox`, I recommend
using [pyenv](https://github.com/pyenv/pyenv) (_do not_ confuse it with `pipenv`,).
1. Commit your changes and push your branch to GitHub:
```shell
@ -118,6 +118,7 @@ Before you submit a pull request, check that it meets these guidelines:
1. The pull request has code, it should include tests.
1. Check that all checks pass on GitHub CI.
1. If something significant changed, modify docs.
## Tips
@ -126,3 +127,13 @@ To run a subset of tests:
```shell
poe test tests/the-tests-file.py
```
### Nix binary cache
Our direnv configuration is configured to use binary caches by default.
However, to add our binary caches permanently:
```shell
nix-shell -p cachix --run 'cachix use copier && cachix use devenv'
```

View File

@ -25,6 +25,7 @@ A library and CLI app for rendering project templates.
1. Install Git 2.27 or newer.
1. To use as a CLI app: `pipx install copier`
1. To use as a library: `pip install copier` or `conda install -c conda-forge copier`
1. To use with 100% reproducibility: `nix profile install github:copier-org/copier`
## Quick start

View File

@ -1,4 +1,7 @@
"""Copier CLI entrypoint."""
from copier.cli import CopierApp
# HACK https://github.com/nix-community/poetry2nix/issues/504
copier_app_run = CopierApp.run
if __name__ == "__main__":
CopierApp.run()
copier_app_run()

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
"""
Command line entrypoint. This module declares the Copier CLI applications.
@ -83,6 +82,7 @@ class CopierApp(cli.Application):
Attributes:
answers_file: Set [answers_file][] option.
conflict: Set [conflict][] option.
exclude: Set [exclude][] option.
vcs_ref: Set [vcs_ref][] option.
pretend: Set [pretend][] option.
@ -356,6 +356,3 @@ if __doc__:
CopierApp.run(["copier", "--help-all"], exit=False)
help_io.seek(0)
__doc__ += f"\n\nCLI help generated from `copier --help-all`:\n\n```\n{help_io.read()}\n```"
if __name__ == "__main__":
CopierApp.run()

View File

@ -77,7 +77,9 @@ class Worker:
Example:
```python
with Worker(src_path="https://github.com/copier-org/autopretty.git", "output") as worker:
with Worker(
src_path="https://github.com/copier-org/autopretty.git", "output"
) as worker:
worker.run_copy()
```
@ -171,9 +173,11 @@ class Worker:
conflict: str = "rej"
def __enter__(self):
"""Allow using worker as a context manager."""
return self
def __exit__(self, type, value, traceback):
"""Clean up garbage files after worker usage ends."""
if value is not None:
# exception was raised from code inside context manager:
# try to clean up, ignoring any exception, then re-raise
@ -302,7 +306,6 @@ class Worker:
"""Determine if a file or directory can be rendered.
Args:
dst_relpath:
Relative path to destination.
is_dir:
@ -473,7 +476,6 @@ class Worker:
"""Render one file.
Args:
src_abspath:
The absolute path to the file that will be rendered.
"""
@ -824,7 +826,7 @@ class Worker:
def run_copy(
src_path: str,
dst_path: StrOrPath = ".",
data: AnyByStrDict = None,
data: Optional[AnyByStrDict] = None,
**kwargs,
) -> Worker:
"""Copy a template to a destination, from zero.
@ -842,7 +844,7 @@ def run_copy(
def run_update(
dst_path: StrOrPath = ".",
data: AnyByStrDict = None,
data: Optional[AnyByStrDict] = None,
**kwargs,
) -> Worker:
"""Update a subproject, from its template.
@ -861,7 +863,7 @@ def run_update(
def run_auto(
src_path: OptStr = None,
dst_path: StrOrPath = ".",
data: AnyByStrDict = None,
data: Optional[AnyByStrDict] = None,
**kwargs,
) -> Worker:
"""Generate or update a subproject.

View File

@ -39,7 +39,7 @@ class Subproject:
answers_relpath: Path = Path(".copier-answers.yml")
def is_dirty(self) -> bool:
"""Indicates if the local template root is dirty.
"""Indicate if the local template root is dirty.
Only applicable for VCS-tracked templates.
"""
@ -50,7 +50,7 @@ class Subproject:
@property
def _raw_answers(self) -> AnyByStrDict:
"""The last answers, loaded raw as yaml."""
"""Get last answers, loaded raw as yaml."""
try:
return yaml.safe_load(
(self.local_abspath / self.answers_relpath).read_text()

View File

@ -360,7 +360,7 @@ class Template:
@cached_property
def min_copier_version(self) -> Optional[Version]:
"""Gets minimal copier version for the template and validates it.
"""Get minimal copier version for the template and validates it.
See [min_copier_version][].
"""

View File

@ -18,16 +18,18 @@ from pydantic import StrictBool
from .types import IntSeq
try:
from importlib.metadata import version
except ImportError:
# Python < 3.8
# TODO Remove condition when dropping python 3.8 support
if sys.version_info < (3, 8):
from importlib_metadata import version
else:
from importlib.metadata import version
colorama.init()
class Style:
"""Common color styles."""
OK: IntSeq = [colorama.Fore.GREEN, colorama.Style.BRIGHT]
WARNING: IntSeq = [colorama.Fore.YELLOW, colorama.Style.BRIGHT]
IGNORE: IntSeq = [colorama.Fore.CYAN]
@ -63,6 +65,7 @@ def printf(
quiet: Union[bool, StrictBool] = False,
file_: TextIO = sys.stdout,
) -> Optional[str]:
"""Print string with common format."""
if quiet:
return None # HACK: Satisfy MyPy
_msg = str(msg)
@ -78,6 +81,7 @@ def printf(
def printf_exception(
e: Exception, action: str, msg: str = "", indent: int = 0, quiet: bool = False
) -> None:
"""Print exception with common format."""
if not quiet:
print("", file=sys.stderr)
printf(action, msg=msg, style=Style.DANGER, indent=indent, file_=sys.stderr)
@ -114,6 +118,7 @@ def cast_str_to_bool(value: Any) -> bool:
def copy_file(src_path: Path, dst_path: Path, follow_symlinks: bool = True) -> None:
"""Copy one file to another place."""
shutil.copy2(src_path, dst_path, follow_symlinks=follow_symlinks)
@ -166,6 +171,7 @@ class TemporaryDirectory(tempfile.TemporaryDirectory):
warnings.warn(warn_message, ResourceWarning)
def cleanup(self):
"""Remove directory safely."""
if self._finalizer.detach():
self._robust_cleanup(self.name)

View File

@ -40,11 +40,14 @@ Env = Mapping[str, str]
class AllowArbitraryTypes:
"""Allow any type for this class."""
arbitrary_types_allowed = True
# Validators
def path_is_absolute(value: Path) -> Path:
"""Require absolute paths in an argument."""
if not value.is_absolute():
from .errors import PathNotAbsoluteError
@ -53,6 +56,7 @@ def path_is_absolute(value: Path) -> Path:
def path_is_relative(value: Path) -> Path:
"""Require relative paths in an argument."""
if value.is_absolute():
from .errors import PathNotRelativeError
@ -67,12 +71,16 @@ if TYPE_CHECKING:
else:
class AbsolutePath(Path):
"""Require absolute paths in an argument."""
@classmethod
def __get_validators__(cls) -> "CallableGenerator":
yield path_validator
yield path_is_absolute
class RelativePath(Path):
"""Require relative paths in an argument."""
@classmethod
def __get_validators__(cls) -> "CallableGenerator":
yield path_validator

View File

@ -135,6 +135,7 @@ class AnswersMap:
)
def old_commit(self) -> OptStr:
"""Commit when the project was updated from this template the last time."""
return self.last.get("_commit")

View File

@ -56,7 +56,7 @@ def is_git_bundle(path: Path) -> bool:
def get_repo(url: str) -> OptStr:
"""Transforms `url` into a git-parseable origin URL.
"""Transform `url` into a git-parseable origin URL.
Args:
url:
@ -133,7 +133,6 @@ def clone(url: str, ref: OptStr = None) -> str:
ref:
Reference to checkout. For Git repos, defaults to `HEAD`.
"""
location = mkdtemp(prefix=f"{__name__}.clone.")
_clone = git["clone", "--no-checkout", url, location]
# Faster clones if possible

14
default.nix Normal file
View File

@ -0,0 +1,14 @@
(
import
(
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
)
{src = ./.;}
)
.defaultNix

View File

@ -1,3 +1,4 @@
"""Development helper tasks."""
import os
import shutil
from pathlib import Path
@ -5,9 +6,7 @@ from subprocess import check_call
def clean():
"""
Clean build, test or other process artefacts from the project workspace
"""
"""Clean build, test or other process artifacts from the project workspace."""
build_artefacts = (
"build/",
"dist/",
@ -33,7 +32,7 @@ def clean():
def dev_setup():
"""Setup a development environment."""
"""Set up a development environment."""
# Gitpod sets PIP_USER=yes, which breaks poetry
env = dict(os.environ, PIP_USER="no")
check_call(["poetry", "install", "--with", "docs"], env=env)

302
flake.lock generated Normal file
View File

@ -0,0 +1,302 @@
{
"nodes": {
"devenv": {
"inputs": {
"flake-compat": "flake-compat",
"nix": "nix",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks"
},
"locked": {
"lastModified": 1671716968,
"narHash": "sha256-LThNtwAXH/0KVMgyTFBwl93ktuWpWTZhCh6NBlydBbQ=",
"owner": "cachix",
"repo": "devenv",
"rev": "ba6818f4c39fd95aebdb6dc441401f2b60484652",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "v0.5",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"devenv",
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1660459072,
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"lowdown-src": {
"flake": false,
"locked": {
"lastModified": 1633514407,
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
"owner": "kristapsdz",
"repo": "lowdown",
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
"type": "github"
},
"original": {
"owner": "kristapsdz",
"repo": "lowdown",
"type": "github"
}
},
"nix": {
"inputs": {
"lowdown-src": "lowdown-src",
"nixpkgs": [
"devenv",
"nixpkgs"
],
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1671638174,
"narHash": "sha256-FeEmVix8l/HglWtRgeHOfjqEm2etvp+MLYd1C/raq3Y=",
"owner": "domenkozar",
"repo": "nix",
"rev": "51b770e985f9e1b84fb5e03a983ef1e19f18c3e9",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "relaxed-flakes",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1671458120,
"narHash": "sha256-2+k/OONN4OF21TeoNjKB5sXVZv6Zvm/uEyQIW9OYCg8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e37ef84b478fa8da0ced96522adfd956fde9047a",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1671271954,
"narHash": "sha256-cSvu+bnvN08sOlTBWbBrKaBHQZq8mvk8bgpt0ZJ2Snc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d513b448cc2a6da2c8803e3c197c9fc7e67b19e3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-22.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1673800717,
"narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1673940514,
"narHash": "sha256-jM1c0V6EBqea9fLMyrfIrB4gbnXrW0gVswYjGdu0JiE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "29a7c9631b7405dcf480138f417682af8a4069c7",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"poetry2nix": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1673926875,
"narHash": "sha256-QOsT76Al0Igpo0u5vtQJuDSOxrocX3sTD523pLPEklc=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "a5c454a834cd290dd4d33102ab8b4aa37d850e65",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": [
"devenv",
"flake-compat"
],
"flake-utils": "flake-utils",
"gitignore": "gitignore",
"nixpkgs": [
"devenv",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1671452357,
"narHash": "sha256-HqzXiQEegpRQ4VEl9pEPgHSIxhJrNJ27HfN1wOc7w2E=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "200790e9c77064c53eaf95805b013d96615ecc27",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"flake-compat": "flake-compat_2",
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2",
"poetry2nix": "poetry2nix"
}
}
},
"root": "root",
"version": 7
}

110
flake.nix Normal file
View File

@ -0,0 +1,110 @@
{
inputs = {
devenv.url = "github:cachix/devenv/v0.5";
flake-compat = {
url = github:edolstra/flake-compat;
flake = false;
};
flake-utils.url = github:numtide/flake-utils;
nixpkgs.url = github:NixOS/nixpkgs/nixos-22.11;
poetry2nix.url = github:nix-community/poetry2nix;
};
outputs = inputs:
with inputs;
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {
inherit system;
overlays = [poetry2nix.overlay];
};
lastRelease = (pkgs.lib.importTOML ./pyproject.toml).tool.commitizen.version;
version = "${lastRelease}.dev${self.sourceInfo.lastModifiedDate}+nix-git-${self.sourceInfo.shortRev or "dirty"}";
# Builders
copierApp = pkgs.poetry2nix.mkPoetryApplication {
inherit version;
name = "copier-${version}";
POETRY_DYNAMIC_VERSIONING_BYPASS = version;
projectDir = ./.;
overrides = pkgs.poetry2nix.overrides.withDefaults (final: prev: {
pydantic = prev.pydantic.overrideAttrs (old: {
buildInputs = old.buildInputs ++ [pkgs.libxcrypt];
});
});
# Test configuration
checkInputs = [pkgs.git];
pythonImportsCheck = ["copier"];
doCheck = true;
installCheckPhase = ''
patchShebangs tests
env \
GIT_AUTHOR_EMAIL=copier@example.com \
GIT_AUTHOR_NAME=copier \
GIT_COMMITTER_EMAIL=copier@example.com \
GIT_COMMITTER_NAME=copier \
PATH=$out/bin:$PATH \
POETRY_VIRTUALENVS_PATH=$NIX_BUILD_TOP/virtualenvs \
PYTHONOPTIMIZE= \
pytest --color=yes -m 'not impure'
'';
};
copierModule = pkgs.python3.pkgs.toPythonModule copierApp;
in rec {
devShells.default = devenv.lib.mkShell {
inherit inputs pkgs;
modules = [
{
packages = with pkgs; [
# Essential dev tools
(pkgs.python3.withPackages (ps:
with ps; [
poetry
poetry-dynamic-versioning
]))
# IDE integration tools
alejandra
black
commitizen
isort
mypy
nodePackages.prettier
];
difftastic.enable = true;
pre-commit.hooks = {
alejandra.enable = true;
black.enable = true;
commitizen.enable = true;
editorconfig-checker.enable = true;
editorconfig-checker.excludes = [
"\.md$"
"\.noeof\."
"\.bundle$"
];
flake8.enable = true;
isort.enable = true;
prettier.enable = true;
prettier.excludes = [
# Those files have wrong syntax and would fail
"^tests/demo_invalid/copier.yml$"
"^tests/demo_transclude_invalid(_multi)?/demo/copier.yml$"
# HACK https://github.com/prettier/prettier/issues/9430
"^tests/demo"
];
};
}
];
};
packages.default = copierModule;
apps =
builtins.mapAttrs
(name: value: flake-utils.lib.mkApp {drv = value;})
packages;
checks =
packages
// {
devenv-ci = devShells.default.ci;
};
});
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -16,21 +16,18 @@
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
inkscape:export-filename="/Users/jps/Projects/copier/copier-logo.png"
inkscape:export-xdpi="118.14733"
inkscape:export-ydpi="118.14733">
<metadata
id="metadata3779">
inkscape:export-ydpi="118.14733"
>
<metadata id="metadata3779">
<rdf:RDF>
<cc:Work
rdf:about="">
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3777" />
<defs id="defs3777" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
@ -52,94 +49,108 @@
inkscape:zoom="1.98"
inkscape:cx="54.825884"
inkscape:cy="5.6908511"
inkscape:current-layer="svg3773" />
<g
id="g4609"
transform="translate(-46.017835,-64.600465)">
inkscape:current-layer="svg3773"
/>
<g id="g4609" transform="translate(-46.017835,-64.600465)">
<path
id="path3789"
style="fill:#dddddd;fill-opacity:1;stroke:#dddddd;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 123.24991,75.191221 17.81702,13.845468 c 4.03331,3.134247 4.75709,8.904518 1.62285,12.937821 l -27.45681,35.33276 c -3.13425,4.03331 -8.90452,4.7571 -12.93783,1.62285 L 84.478114,125.08465 c -4.03332,-3.13424 -4.7571,-8.90452 -1.62285,-12.93783 L 110.31207,76.814066 c 3.13425,-4.033308 8.90452,-4.757096 12.93784,-1.622845 z m -19.88432,-4.519638 20.53044,9.361854 c 4.64755,2.119276 6.68294,7.566941 4.56367,12.214494 l -18.5654,40.713719 c -2.11928,4.64755 -7.56694,6.68295 -12.214496,4.56367 l -20.530438,-9.36185 c -4.647556,-2.11927 -6.682954,-7.56694 -4.563679,-12.2145 L 91.151084,75.235257 c 2.11928,-4.647554 7.56695,-6.682951 12.214506,-4.563674 z m -15.929666,-0.941169 22.248486,3.76145 c 5.03647,0.851492 8.3594,5.58354 7.45052,10.609973 l -7.96203,44.032793 c -0.90888,5.02643 -5.69521,8.38748 -10.731676,7.53599 L 76.19274,131.90917 c -5.036474,-0.8515 -8.359407,-5.58354 -7.450526,-10.60997 l 7.962027,-44.032795 c 0.908882,-5.026433 5.695213,-8.387485 10.731683,-7.535991 z m -14.041662,2.732 22.546252,-0.900074 c 5.103856,-0.203752 9.376796,3.741113 9.580546,8.844992 l 1.78493,44.711238 c 0.20375,5.10387 -3.74111,9.3768 -8.844976,9.58055 l -22.546252,0.90007 c -5.103881,0.20376 -9.376811,-3.74111 -9.580563,-8.84498 L 64.549271,82.042976 c -0.203754,-5.103879 3.741113,-9.376809 8.844991,-9.580562 z m -15.955511,6.057349 21.50141,-6.843458 c 4.867353,-1.549178 10.033003,1.122133 11.582183,5.989487 l 13.571186,42.639218 c 1.54918,4.86735 -1.12213,10.033 -5.989476,11.58218 l -21.501411,6.84346 c -4.867356,1.54918 -10.033012,-1.12213 -11.582189,-5.98948 L 51.449263,90.101952 c -1.549179,-4.867354 1.122131,-10.03301 5.989488,-11.582189 z"
inkscape:connector-curvature="0" />
<g
id="g3771"
transform="translate(-0.801806,-1.5851988)">
inkscape:connector-curvature="0"
/>
<g id="g3771" transform="translate(-0.801806,-1.5851988)">
<path
id="path3761"
style="fill:#3bb3c4;fill-opacity:1;stroke:#ffffff;stroke-width:2.42168283;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 58.240557,80.104962 21.50141,-6.843458 c 4.867351,-1.549178 10.033006,1.122133 11.582184,5.989487 l 13.571189,42.639219 c 1.54918,4.86735 -1.12213,10.033 -5.989477,11.58218 l -21.501414,6.84346 c -4.867356,1.54918 -10.033012,-1.12213 -11.582189,-5.98948 L 52.251069,91.687151 C 50.70189,86.819797 53.3732,81.654141 58.240557,80.104962 Z"
inkscape:connector-curvature="0" />
inkscape:connector-curvature="0"
/>
<path
id="path3763"
style="fill:#b74f8e;fill-opacity:1;stroke:#ffffff;stroke-width:2.42168283;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 74.196068,74.047613 22.546257,-0.900074 c 5.103855,-0.203752 9.376795,3.741113 9.580545,8.844992 l 1.78493,44.711239 c 0.20375,5.10387 -3.74111,9.3768 -8.844979,9.58055 l -22.546253,0.90007 c -5.103881,0.20376 -9.376811,-3.74111 -9.580563,-8.84498 L 65.351077,83.628175 c -0.203754,-5.103879 3.741113,-9.376809 8.844991,-9.580562 z"
inkscape:connector-curvature="0" />
inkscape:connector-curvature="0"
/>
<path
id="path3765"
style="fill:#e91414;fill-opacity:1;stroke:#ffffff;stroke-width:2.42160416;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 88.237734,71.315613 22.248486,3.76145 c 5.03647,0.851492 8.3594,5.58354 7.45052,10.609973 l -7.96203,44.032794 c -0.90888,5.02643 -5.69521,8.38748 -10.731683,7.53599 l -22.248481,-3.76145 c -5.036474,-0.8515 -8.359407,-5.58354 -7.450526,-10.60997 l 7.962027,-44.032796 c 0.908882,-5.026433 5.695213,-8.387485 10.731687,-7.535991 z"
inkscape:connector-curvature="0" />
inkscape:connector-curvature="0"
/>
<path
id="path3767"
style="fill:#e57813;fill-opacity:1;stroke:#ffffff;stroke-width:2.42168283;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 104.1674,72.256782 20.53044,9.361854 c 4.64755,2.119276 6.68294,7.566941 4.56367,12.214494 l -18.5654,40.71372 c -2.11928,4.64755 -7.56694,6.68295 -12.214496,4.56367 l -20.530442,-9.36185 c -4.647556,-2.11927 -6.682954,-7.56694 -4.563679,-12.2145 L 91.952891,76.820456 c 2.119279,-4.647554 7.566948,-6.682951 12.214509,-4.563674 z"
inkscape:connector-curvature="0" />
inkscape:connector-curvature="0"
/>
<path
id="path3769"
style="fill:#f8c301;fill-opacity:0.9905213;stroke:#ffffff;stroke-width:2.42168283;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 124.05172,76.77642 17.81702,13.845468 c 4.03331,3.134247 4.75709,8.904518 1.62285,12.937822 l -27.45681,35.33276 c -3.13425,4.03331 -8.90452,4.7571 -12.93783,1.62285 L 85.279918,126.66985 c -4.033313,-3.13424 -4.757099,-8.90452 -1.622847,-12.93783 L 111.11388,78.399265 c 3.13425,-4.033308 8.90452,-4.757096 12.93784,-1.622845 z"
inkscape:connector-curvature="0" />
inkscape:connector-curvature="0"
/>
</g>
</g>
<g
id="g4656"
transform="translate(-22)">
<g id="g4656" transform="translate(-22)">
<g
transform="translate(40)"
id="text4617"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;line-height:1.25;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
aria-label="Copier">
aria-label="Copier"
>
<path
inkscape:connector-curvature="0"
id="path4619"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 80.853458,28.297318 v -2.525313 h 2.920845 v 7.34775 h -2.981696 q -1.125742,-2.205847 -3.088185,-3.438078 -1.962443,-1.232231 -4.305204,-1.232231 -2.266697,0 -4.046587,1.201806 -1.779889,1.186593 -2.78393,3.194674 -0.988827,1.992868 -0.988827,4.28999 0,2.373187 1.034465,4.381268 1.049679,2.00808 2.875207,3.209886 1.825528,1.201806 4.0618,1.201806 2.753505,0 4.868074,-1.6734 2.11457,-1.688614 3.088185,-4.776799 l 2.920845,1.551699 q -1.186593,3.833609 -4.198714,5.948179 -2.996909,2.099357 -7.043496,2.099357 -3.331588,0 -5.917753,-1.582124 -2.586165,-1.597337 -4.031374,-4.274778 -1.429997,-2.692654 -1.429997,-5.902541 0,-3.483716 1.460422,-6.206795 1.475635,-2.723079 4.0618,-4.213927 2.586165,-1.506061 5.917753,-1.506061 2.236272,0 4.122651,0.745424 1.886379,0.745424 3.483716,2.160208 z" />
d="m 80.853458,28.297318 v -2.525313 h 2.920845 v 7.34775 h -2.981696 q -1.125742,-2.205847 -3.088185,-3.438078 -1.962443,-1.232231 -4.305204,-1.232231 -2.266697,0 -4.046587,1.201806 -1.779889,1.186593 -2.78393,3.194674 -0.988827,1.992868 -0.988827,4.28999 0,2.373187 1.034465,4.381268 1.049679,2.00808 2.875207,3.209886 1.825528,1.201806 4.0618,1.201806 2.753505,0 4.868074,-1.6734 2.11457,-1.688614 3.088185,-4.776799 l 2.920845,1.551699 q -1.186593,3.833609 -4.198714,5.948179 -2.996909,2.099357 -7.043496,2.099357 -3.331588,0 -5.917753,-1.582124 -2.586165,-1.597337 -4.031374,-4.274778 -1.429997,-2.692654 -1.429997,-5.902541 0,-3.483716 1.460422,-6.206795 1.475635,-2.723079 4.0618,-4.213927 2.586165,-1.506061 5.917753,-1.506061 2.236272,0 4.122651,0.745424 1.886379,0.745424 3.483716,2.160208 z"
/>
<path
inkscape:connector-curvature="0"
id="path4621"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 103.91596,40.726121 q 0,2.327549 -1.11053,4.259566 -1.11053,1.932017 -3.027332,3.057759 -1.916804,1.125742 -4.244352,1.125742 -2.403612,0 -4.335629,-1.125742 -1.932017,-1.125742 -3.012121,-3.057759 -1.064892,-1.932017 -1.064892,-4.259566 0,-2.434037 1.064892,-4.350841 1.080104,-1.916805 2.996908,-2.996909 1.916805,-1.095317 4.350842,-1.095317 2.357974,0 4.274778,1.156168 1.916806,1.140955 3.012126,3.072972 1.09531,1.932017 1.09531,4.213927 z m -8.382214,5.385308 q 1.399571,0 2.570952,-0.730211 1.17138,-0.730211 1.825528,-1.962443 0.654144,-1.232231 0.654144,-2.692654 0,-1.429996 -0.654144,-2.662228 -0.654148,-1.232231 -1.825528,-1.977655 -1.171381,-0.760637 -2.601378,-0.760637 -1.399571,0 -2.570951,0.745424 -1.171381,0.730211 -1.840741,1.977655 -0.66936,1.247445 -0.66936,2.677441 0,1.429997 0.66936,2.677442 0.66936,1.247444 1.855953,1.977655 1.186593,0.730211 2.586165,0.730211 z" />
d="m 103.91596,40.726121 q 0,2.327549 -1.11053,4.259566 -1.11053,1.932017 -3.027332,3.057759 -1.916804,1.125742 -4.244352,1.125742 -2.403612,0 -4.335629,-1.125742 -1.932017,-1.125742 -3.012121,-3.057759 -1.064892,-1.932017 -1.064892,-4.259566 0,-2.434037 1.064892,-4.350841 1.080104,-1.916805 2.996908,-2.996909 1.916805,-1.095317 4.350842,-1.095317 2.357974,0 4.274778,1.156168 1.916806,1.140955 3.012126,3.072972 1.09531,1.932017 1.09531,4.213927 z m -8.382214,5.385308 q 1.399571,0 2.570952,-0.730211 1.17138,-0.730211 1.825528,-1.962443 0.654144,-1.232231 0.654144,-2.692654 0,-1.429996 -0.654144,-2.662228 -0.654148,-1.232231 -1.825528,-1.977655 -1.171381,-0.760637 -2.601378,-0.760637 -1.399571,0 -2.570951,0.745424 -1.171381,0.730211 -1.840741,1.977655 -0.66936,1.247445 -0.66936,2.677441 0,1.429997 0.66936,2.677442 0.66936,1.247444 1.855953,1.977655 1.186593,0.730211 2.586165,0.730211 z"
/>
<path
inkscape:connector-curvature="0"
id="path4623"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 124.95517,40.786972 q 0,2.236272 -1.03446,4.183502 -1.03447,1.94723 -2.82957,3.072972 -1.77989,1.125742 -3.95531,1.125742 -3.20989,0 -5.6135,-2.464462 v 6.358922 h 3.11861 v 2.799143 h -9.15807 v -2.799143 h 2.89042 V 35.523367 h -2.67744 v -2.814356 h 5.82648 v 2.555739 q 1.18659,-1.399571 2.61659,-2.084144 1.42999,-0.684573 3.05776,-0.684573 2.26669,0 4.03137,1.125742 1.76468,1.11053 2.73829,3.012121 0.98883,1.901592 0.98883,4.153076 z m -7.86498,5.50701 q 1.30829,0 2.35797,-0.760637 1.04968,-0.760637 1.64298,-2.068932 0.59329,-1.308295 0.59329,-2.768717 0,-1.475635 -0.65414,-2.707867 -0.65415,-1.247444 -1.79511,-1.977655 -1.14095,-0.745424 -2.57095,-0.745424 -1.49085,0 -2.67744,0.791062 -1.18659,0.77585 -1.84074,2.068932 -0.65415,1.293082 -0.65415,2.844781 0,2.494888 1.56691,3.909673 1.58213,1.414784 4.03138,1.414784 z" />
d="m 124.95517,40.786972 q 0,2.236272 -1.03446,4.183502 -1.03447,1.94723 -2.82957,3.072972 -1.77989,1.125742 -3.95531,1.125742 -3.20989,0 -5.6135,-2.464462 v 6.358922 h 3.11861 v 2.799143 h -9.15807 v -2.799143 h 2.89042 V 35.523367 h -2.67744 v -2.814356 h 5.82648 v 2.555739 q 1.18659,-1.399571 2.61659,-2.084144 1.42999,-0.684573 3.05776,-0.684573 2.26669,0 4.03137,1.125742 1.76468,1.11053 2.73829,3.012121 0.98883,1.901592 0.98883,4.153076 z m -7.86498,5.50701 q 1.30829,0 2.35797,-0.760637 1.04968,-0.760637 1.64298,-2.068932 0.59329,-1.308295 0.59329,-2.768717 0,-1.475635 -0.65414,-2.707867 -0.65415,-1.247444 -1.79511,-1.977655 -1.14095,-0.745424 -2.57095,-0.745424 -1.49085,0 -2.67744,0.791062 -1.18659,0.77585 -1.84074,2.068932 -0.65415,1.293082 -0.65415,2.844781 0,2.494888 1.56691,3.909673 1.58213,1.414784 4.03138,1.414784 z"
/>
<path
inkscape:connector-curvature="0"
id="path4625"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 132.7593,27.323703 q 0,0.77585 -0.56287,1.338721 -0.56287,0.562871 -1.33872,0.562871 -0.77585,0 -1.32351,-0.562871 -0.54766,-0.562871 -0.54766,-1.338721 0,-0.775849 0.54766,-1.33872 0.54766,-0.562871 1.32351,-0.562871 0.80627,0 1.35393,0.547658 0.54766,0.547659 0.54766,1.353933 z m 2.25149,18.574748 v 2.799143 h -8.07797 v -2.799143 h 2.49489 V 35.523367 h -2.49489 v -2.814356 h 5.64393 v 13.18944 z" />
d="m 132.7593,27.323703 q 0,0.77585 -0.56287,1.338721 -0.56287,0.562871 -1.33872,0.562871 -0.77585,0 -1.32351,-0.562871 -0.54766,-0.562871 -0.54766,-1.338721 0,-0.775849 0.54766,-1.33872 0.54766,-0.562871 1.32351,-0.562871 0.80627,0 1.35393,0.547658 0.54766,0.547659 0.54766,1.353933 z m 2.25149,18.574748 v 2.799143 h -8.07797 v -2.799143 h 2.49489 V 35.523367 h -2.49489 v -2.814356 h 5.64393 v 13.18944 z"
/>
<path
inkscape:connector-curvature="0"
id="path4627"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 153.7833,41.501971 h -13.40242 q 0.28904,2.297123 1.77989,3.635843 1.49085,1.323508 3.65106,1.323508 1.58212,0 2.93605,-0.654148 1.35394,-0.654147 2.2667,-2.00808 l 2.76872,1.247444 q -1.3083,2.038506 -3.43808,3.088185 -2.11457,1.034465 -4.60946,1.034465 -2.58616,0 -4.59424,-1.080104 -2.00808,-1.080104 -3.13383,-3.012121 -1.11053,-1.932017 -1.11053,-4.350842 0,-2.403611 1.09532,-4.335629 1.11053,-1.932017 3.02734,-3.012121 1.9168,-1.095317 4.22914,-1.095317 2.52531,0 4.39647,1.125743 1.88638,1.110529 2.96649,3.194674 1.0801,2.068931 1.17138,4.8985 z m -8.47349,-6.602326 q -1.77989,0 -3.11861,1.201806 -1.33872,1.186593 -1.71904,3.149035 h 10.00998 q -0.44117,-1.962442 -1.87117,-3.149035 -1.43,-1.201806 -3.30116,-1.201806 z" />
d="m 153.7833,41.501971 h -13.40242 q 0.28904,2.297123 1.77989,3.635843 1.49085,1.323508 3.65106,1.323508 1.58212,0 2.93605,-0.654148 1.35394,-0.654147 2.2667,-2.00808 l 2.76872,1.247444 q -1.3083,2.038506 -3.43808,3.088185 -2.11457,1.034465 -4.60946,1.034465 -2.58616,0 -4.59424,-1.080104 -2.00808,-1.080104 -3.13383,-3.012121 -1.11053,-1.932017 -1.11053,-4.350842 0,-2.403611 1.09532,-4.335629 1.11053,-1.932017 3.02734,-3.012121 1.9168,-1.095317 4.22914,-1.095317 2.52531,0 4.39647,1.125743 1.88638,1.110529 2.96649,3.194674 1.0801,2.068931 1.17138,4.8985 z m -8.47349,-6.602326 q -1.77989,0 -3.11861,1.201806 -1.33872,1.186593 -1.71904,3.149035 h 10.00998 q -0.44117,-1.962442 -1.87117,-3.149035 -1.43,-1.201806 -3.30116,-1.201806 z"
/>
<path
inkscape:connector-curvature="0"
id="path4629"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#dddddd;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 162.01339,42.27782 v 3.620631 h 3.48372 v 2.799143 h -9.81222 v -2.799143 h 3.20989 V 35.523367 h -3.20989 v -2.814356 h 5.70478 v 3.620631 q 0.9584,-2.144996 2.37318,-2.981696 1.43,-0.851913 4.07702,-0.851913 h 0.715 v 3.179461 h -0.68458 q -2.55574,0 -3.80318,0.66936 -1.24744,0.669361 -1.65819,2.023294 -0.39553,1.353933 -0.39553,3.909672 z" />
d="m 162.01339,42.27782 v 3.620631 h 3.48372 v 2.799143 h -9.81222 v -2.799143 h 3.20989 V 35.523367 h -3.20989 v -2.814356 h 5.70478 v 3.620631 q 0.9584,-2.144996 2.37318,-2.981696 1.43,-0.851913 4.07702,-0.851913 h 0.715 v 3.179461 h -0.68458 q -2.55574,0 -3.80318,0.66936 -1.24744,0.669361 -1.65819,2.023294 -0.39553,1.353933 -0.39553,3.909672 z"
/>
</g>
<text
id="text4613"
y="48.697594"
x="100.25542"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;line-height:1.25;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.77889198"
xml:space="preserve"><tspan
xml:space="preserve"
>
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.1556778px;font-family:Rockwell;-inkscape-font-specification:'Rockwell, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.77889198"
y="48.697594"
x="100.25542"
id="tspan4611"
sodipodi:role="line">Copier</tspan></text>
sodipodi:role="line"
>
Copier
</tspan>
</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

1028
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ repository = "https://github.com/copier-org/copier"
readme = "README.md"
[tool.poetry.scripts]
copier = "copier.cli:CopierApp.run"
copier = "copier.__main__:copier_app_run"
[tool.poetry.urls]
"Bug Tracker" = "https://github.com/copier-org/copier/issues"
@ -44,25 +44,20 @@ pyyaml-include = ">=1.2"
questionary = ">=1.8.1"
typing-extensions = { version = ">=3.7.4,<5.0.0", python = "<3.8" }
[tool.poetry.group.dev]
optional = true
[tool.poetry.group.dev.dependencies]
autoflake = ">=1.4"
black = ">=22.1"
commitizen = ">=2.32.2"
flake8 = ">=4.0.1"
flake8-bugbear = ">=22.1.11"
flake8-comprehensions = ">=3.8.0"
flake8-debugger = ">=4.0.0"
flake8-simplify = ">=0.19.3"
isort = ">=5.10.1"
mypy = ">=0.931"
pexpect = ">=4.8.0"
poethepoet = ">=0.12.3"
pre-commit = ">=2.17.0"
pytest = ">=7.0.1"
pytest = ">=7.2.0"
pytest-cov = ">=3.0.0"
pytest-xdist = ">=2.5.0"
types-backports = ">=0.1.3"
types-pyyaml = ">=6.0.4"
types-psutil = "*"
[tool.poetry.group.docs]
optional = true
@ -117,8 +112,15 @@ ignore_missing_imports = true
plugins = ["pydantic.mypy"]
warn_no_return = false
[tool.pydocstyle]
match_dir = "^copier"
add_ignore = ["D105", "D107"]
[tool.pytest.ini_options]
addopts = "-n auto -ra"
markers = [
"impure: needs network or is not 100% reproducible"
]
[tool.commitizen]
annotated_tag = true
@ -128,5 +130,5 @@ update_changelog_on_bump = true
version = "7.1.0a0"
[build-system]
requires = ["poetry_core>=1.0.0", "poetry-dynamic-versioning"]
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
build-backend = "poetry_dynamic_versioning.backend"

12
shell.nix Normal file
View File

@ -0,0 +1,12 @@
{lock ? builtins.fromJSON (builtins.readFile ./flake.lock)}:
(
import
(
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
)
{src = ./.;}
)
.shellNix

View File

@ -134,6 +134,7 @@ def test_copy(tmp_path):
assert os.path.exists(tmp_path / "py3_folder" / "thing.py")
@pytest.mark.impure
def test_copy_repo(tmp_path):
copier.copy(
"gh:copier-org/copier.git",

View File

@ -1,24 +1,12 @@
import platform
from pathlib import Path
from stat import S_IREAD
import pytest
from plumbum.cmd import git
from poethepoet.app import PoeThePoet
from copier.tools import TemporaryDirectory
@pytest.mark.skipif(
condition=platform.system() == "Windows",
reason="Windows does weird things with line endings.",
)
def test_lint():
"""Ensure source code formatting"""
result = PoeThePoet(Path("."))(["lint", "--show-diff-on-failure", "--color=always"])
assert result == 0
def test_types():
"""Ensure source code static typing."""
result = PoeThePoet(Path("."))(["types"])
@ -38,5 +26,5 @@ def test_temporary_directory_with_readonly_files_deletion():
def test_temporary_directory_with_git_repo_deletion():
"""Ensure temporary directories containing git repositories are properly deleted, whatever the OS."""
with TemporaryDirectory() as tmp_dir:
git("clone", "--depth=1", ".", Path(tmp_dir) / "repo")
git("init")
assert not Path(tmp_dir).exists()

View File

@ -17,6 +17,7 @@ from copier.types import RelativePath
from .helpers import BRACKET_ENVOPS_JSON, SUFFIX_TMPL, build_file_tree
@pytest.mark.impure
def test_updatediff(tmp_path_factory):
src, dst = map(tmp_path_factory.mktemp, ("src", "dst"))
# Prepare repo bundle
@ -285,6 +286,7 @@ def test_updatediff(tmp_path_factory):
@pytest.mark.xfail(
condition=platform.system() == "Windows", reason="Git broken on Windows?"
)
@pytest.mark.impure
def test_commit_hooks_respected(tmp_path_factory):
"""Commit hooks are taken into account when producing the update diff."""
# Prepare source template v1
@ -476,7 +478,7 @@ def test_skip_update(tmp_path_factory):
git("commit", "-m1")
git("tag", "1.0.0")
run_copy(str(src), dst, defaults=True, overwrite=True)
skip_me: Path = dst / "skip_me"
skip_me = dst / "skip_me"
answers_file = dst / ".copier-answers.yml"
answers = yaml.safe_load(answers_file.read_text())
assert skip_me.read_text() == "1"

View File

@ -3,6 +3,7 @@ import shutil
from os.path import exists, join
from pathlib import Path
import pytest
from plumbum import local
from plumbum.cmd import git
@ -60,6 +61,7 @@ def test_get_repo():
)
@pytest.mark.impure
def test_clone():
tmp = vcs.clone("https://github.com/copier-org/copier.git")
assert tmp
@ -67,6 +69,7 @@ def test_clone():
shutil.rmtree(tmp, ignore_errors=True)
@pytest.mark.impure
def test_removes_temporary_clone(tmp_path):
src_path = "https://github.com/copier-org/autopretty.git"
with Worker(src_path=src_path, dst_path=tmp_path, defaults=True) as worker:
@ -75,6 +78,7 @@ def test_removes_temporary_clone(tmp_path):
assert not temp_clone.exists()
@pytest.mark.impure
def test_dont_remove_local_clone(tmp_path):
src_path = vcs.clone("https://github.com/copier-org/autopretty.git")
with Worker(src_path=src_path, dst_path=tmp_path, defaults=True) as worker:
@ -82,6 +86,7 @@ def test_dont_remove_local_clone(tmp_path):
assert exists(src_path)
@pytest.mark.impure
def test_update_using_local_source_path_with_tilde(tmp_path):
# first, get a local repository clone
src_path = vcs.clone("https://github.com/copier-org/autopretty.git")