dk-tasklib 3.0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dk_tasklib-3.0.9.dist-info/METADATA +78 -0
- dk_tasklib-3.0.9.dist-info/RECORD +35 -0
- dk_tasklib-3.0.9.dist-info/WHEEL +5 -0
- dk_tasklib-3.0.9.dist-info/entry_points.txt +2 -0
- dk_tasklib-3.0.9.dist-info/top_level.txt +1 -0
- dktasklib/__init__.py +3 -0
- dktasklib/_version.py +1 -0
- dktasklib/clean.py +8 -0
- dktasklib/commands.py +95 -0
- dktasklib/concat.py +76 -0
- dktasklib/docs.py +225 -0
- dktasklib/entry_points/__init__.py +5 -0
- dktasklib/entry_points/confbase.py +172 -0
- dktasklib/entry_points/dktasklibcmd.py +102 -0
- dktasklib/entry_points/pytemplate.py +16 -0
- dktasklib/entry_points/taskbase.py +135 -0
- dktasklib/environment.py +11 -0
- dktasklib/executables.py +200 -0
- dktasklib/help.py +17 -0
- dktasklib/jstools.py +320 -0
- dktasklib/lessc.py +111 -0
- dktasklib/manage.py +71 -0
- dktasklib/npm.py +19 -0
- dktasklib/package/__init__.py +31 -0
- dktasklib/package/package_interface.py +103 -0
- dktasklib/pset.py +122 -0
- dktasklib/publish.py +50 -0
- dktasklib/rule.py +65 -0
- dktasklib/runners.py +40 -0
- dktasklib/upversion.py +165 -0
- dktasklib/urlinliner.py +90 -0
- dktasklib/utils.py +234 -0
- dktasklib/version.py +103 -0
- dktasklib/watch.py +90 -0
- dktasklib/wintask.py +4 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dk-tasklib
|
|
3
|
+
Version: 3.0.9
|
|
4
|
+
Summary: dk-tasklib - pyinvoke task library
|
|
5
|
+
Home-page: https://github.com/datakortet/dk-tasklib
|
|
6
|
+
Author: Bjorn Pettersen
|
|
7
|
+
Author-email: bp@datakortet.no
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Requires-Dist: invoke
|
|
17
|
+
Requires-Dist: PyYAML
|
|
18
|
+
Requires-Dist: dkfileutils>=1.4.2
|
|
19
|
+
Requires-Dist: yamldirs>=1.1.8
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: requires-dist
|
|
26
|
+
Dynamic: summary
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
.. image:: https://travis-ci.org/datakortet/dk-tasklib.svg?branch=master
|
|
30
|
+
:target: https://travis-ci.org/datakortet/dk-tasklib
|
|
31
|
+
|
|
32
|
+
.. image:: https://coveralls.io/repos/github/datakortet/dk-tasklib/badge.svg?branch=master
|
|
33
|
+
:target: https://coveralls.io/github/datakortet/dk-tasklib?branch=master
|
|
34
|
+
|
|
35
|
+
dk-tasklib - pyinvoke task library
|
|
36
|
+
====================================
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
Installing from PyPI
|
|
40
|
+
--------------------
|
|
41
|
+
|
|
42
|
+
This is what you want if you just want to use dk-tasklib:
|
|
43
|
+
|
|
44
|
+
pip install dk-tasklib
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
Creating a default tasks.py file
|
|
48
|
+
--------------------------------
|
|
49
|
+
You can create a default ``tasks.py`` file. From the root of your package::
|
|
50
|
+
|
|
51
|
+
dk-tasklib install
|
|
52
|
+
|
|
53
|
+
You'll need to specify ``--force`` to overwrite an existing file.
|
|
54
|
+
|
|
55
|
+
As a source package
|
|
56
|
+
-------------------
|
|
57
|
+
This is what you want if you are developing dk-tasklib or want
|
|
58
|
+
to make local changes to the source code.
|
|
59
|
+
|
|
60
|
+
pip install -e <path>
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
See docs/ folder for documentation.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
Development
|
|
67
|
+
-----------
|
|
68
|
+
|
|
69
|
+
Run the authoritative package checks from the repository root::
|
|
70
|
+
|
|
71
|
+
dk testpackage
|
|
72
|
+
|
|
73
|
+
The suite enforces branch-aware coverage of at least 83 percent. Build the
|
|
74
|
+
documentation with::
|
|
75
|
+
|
|
76
|
+
dk docs
|
|
77
|
+
|
|
78
|
+
The documentation is maintained against current Sphinx 8 and 9 releases.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
dktasklib/__init__.py,sha256=XEy0mO984KPXEXIbohLYDjl_7UeV2tiuM58BVfyIKlQ,129
|
|
2
|
+
dktasklib/_version.py,sha256=GgzlXELdHTkTAUXqLnCAGFr2E0nwjjBPe-3RxfSkl6c,22
|
|
3
|
+
dktasklib/clean.py,sha256=m4IF-XI6J5KJz7WvWDYoA7Sr65OI7K3GR9IcJsKAQ2Y,212
|
|
4
|
+
dktasklib/commands.py,sha256=bh8aF8RYBfCgOwhWmGsRpGeyeZl5EXbOHUL11OOTNc4,3165
|
|
5
|
+
dktasklib/concat.py,sha256=GfAqc94dS8Lki25RIMaCx4_A8iVsKN6mTJjQZwW-rk4,1942
|
|
6
|
+
dktasklib/docs.py,sha256=1iIOUE4mKTksTbRLcDZ2vNz3PltgdNlbANii2_iGRKc,6463
|
|
7
|
+
dktasklib/environment.py,sha256=3eX8e-z4C94tcim6vw5mWOiD6952PWG0EaW1-bWin40,113
|
|
8
|
+
dktasklib/executables.py,sha256=1puqMZ1ni87V0a0sQsF5iGNvXtmaF7MCD25Gst9P6no,6621
|
|
9
|
+
dktasklib/help.py,sha256=FNKuVusc-Dev8ihEk98mmxY9WNUEwi-6F7IikHW6EQo,359
|
|
10
|
+
dktasklib/jstools.py,sha256=W4kBh7xPJsiZb2U4r2HPrKCufsx9Zya7lyXA3PIg_OQ,10535
|
|
11
|
+
dktasklib/lessc.py,sha256=Gx0jUHz02QXnxevQGDSdy045VpLSA2PGNITa6LJqzRo,3375
|
|
12
|
+
dktasklib/manage.py,sha256=0S1PAjAfJctjT6RCNLw4pvBst83rP_TaeUk-QLXP4VU,2631
|
|
13
|
+
dktasklib/npm.py,sha256=6W2AmYptF6sWNAdrgefDGHDcYAUDBVF1pIprLNDyb4Q,518
|
|
14
|
+
dktasklib/pset.py,sha256=L656kmzR4OXIsHni2OPQAVm6ctw-O0_YScOnZCVYV-s,3304
|
|
15
|
+
dktasklib/publish.py,sha256=j8rZ2VXnDd4ak3GXvmy4zDpDnzsRqbJAgB7dvKijyec,1361
|
|
16
|
+
dktasklib/rule.py,sha256=6D85tS3tIgiK9ll_0leaGH-rUsFqTA0oZqqW8W-Dg8o,1572
|
|
17
|
+
dktasklib/runners.py,sha256=OvGY-3ljyX-SYxf7rib9CWMLa0Whaoxvgc_tyfO2URw,990
|
|
18
|
+
dktasklib/upversion.py,sha256=CppaS2nIx9KhjB-wb03LWIkNfzkFdm7xNhLYBa2w6aI,5166
|
|
19
|
+
dktasklib/urlinliner.py,sha256=vSBUOVD9mqfSJkMCiPYjWwU62RVtG346rIkJKc6qMi4,2505
|
|
20
|
+
dktasklib/utils.py,sha256=tqP0VCYi4ulP63deJhsg3XO3e7FEl0cMzkXj2LKPb4s,6845
|
|
21
|
+
dktasklib/version.py,sha256=QbZ6_WbnWwX1okaf0hkPRoQLv9Bmyn_GB_rzwDsk0rI,2599
|
|
22
|
+
dktasklib/watch.py,sha256=qm4oE-8y8GNg7esYyc90O9u9Koug2LwvxxSrUkTUcVM,2416
|
|
23
|
+
dktasklib/wintask.py,sha256=gb7JnDmiV9O-nDOTUq_Kci02_PR3v5J4GpK7M6ffR3M,45
|
|
24
|
+
dktasklib/entry_points/__init__.py,sha256=1vjEu0jaBda00GRE2eJrronfxy0TaCSUTe4jUikzw1U,45
|
|
25
|
+
dktasklib/entry_points/confbase.py,sha256=3GFatqsGxo0c4DZYgWLgJdWri7AVspqSS96PhWOLeSo,5352
|
|
26
|
+
dktasklib/entry_points/dktasklibcmd.py,sha256=fTulpX9lQa7H_iUNNuJxMCeHTRfF7V2Ylgv-oTEVFNo,2824
|
|
27
|
+
dktasklib/entry_points/pytemplate.py,sha256=po3Xybr9xuRM4BABVwBgyyd525jJNUU6Q8clp5wPcnQ,431
|
|
28
|
+
dktasklib/entry_points/taskbase.py,sha256=LquiNxt5kYVztBG8xBtrTwRfF7DtDhTBiY2j8GiyjfM,4021
|
|
29
|
+
dktasklib/package/__init__.py,sha256=K_ojfTu6ebW0ETjXUrUZTrluJS0OWcjigdNAATd6ga4,1138
|
|
30
|
+
dktasklib/package/package_interface.py,sha256=vICO-4Y0Zjuwyba_ERlZoexFT9TlZH0bhsn_qFKz2cw,3068
|
|
31
|
+
dk_tasklib-3.0.9.dist-info/METADATA,sha256=HtrAsqA0B-X4gYuLBzf-YIdkjoY9dv3KK22XY3giFZM,2087
|
|
32
|
+
dk_tasklib-3.0.9.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
33
|
+
dk_tasklib-3.0.9.dist-info/entry_points.txt,sha256=3ay7Osx3BNuj1RbAquh72G6hTkL9FYNyydH1G45uT6M,72
|
|
34
|
+
dk_tasklib-3.0.9.dist-info/top_level.txt,sha256=yG3xqUjpFZUCFf-_OhR5X2Is0NVbOW6e9YBmYnFlwhU,10
|
|
35
|
+
dk_tasklib-3.0.9.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dktasklib
|
dktasklib/__init__.py
ADDED
dktasklib/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '3.0.9'
|
dktasklib/clean.py
ADDED
dktasklib/commands.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import invoke
|
|
4
|
+
|
|
5
|
+
from .executables import exe
|
|
6
|
+
from .utils import fmt
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
default_command_policy = dict(
|
|
10
|
+
negative_bool='omit', # omit False boolean parameters (or 'prefix')
|
|
11
|
+
list_join=',',
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Command:
|
|
16
|
+
def __init__(self, name, argspec="",
|
|
17
|
+
requirements=(),
|
|
18
|
+
policy=default_command_policy,
|
|
19
|
+
**optdefs):
|
|
20
|
+
self._args = (name, argspec, requirements, policy, optdefs)
|
|
21
|
+
self._initialized = False
|
|
22
|
+
|
|
23
|
+
def _initialize(self):
|
|
24
|
+
if self._initialized:
|
|
25
|
+
return
|
|
26
|
+
name, argspec, requirements, policy, optdefs = self._args
|
|
27
|
+
# handle any required params attached to the command, i.e. if the
|
|
28
|
+
# command is specified as foo = Command('foo -v', ...)
|
|
29
|
+
exename, reqparams = (name + ' ').split(' ', 1)
|
|
30
|
+
# make sure all requirements are present
|
|
31
|
+
exe.require(*requirements)
|
|
32
|
+
if os.path.isfile(exename): # if path to executable is given
|
|
33
|
+
self.cmd = exename # then use it
|
|
34
|
+
else:
|
|
35
|
+
self.cmd = exe.find(exename) # else search path
|
|
36
|
+
# fetch names of all argspec params
|
|
37
|
+
self.params = [p[1:-1] for p in re.findall(r'\{[^}]*\}', argspec)]
|
|
38
|
+
self.required_params = reqparams.strip()
|
|
39
|
+
self.argspec = argspec
|
|
40
|
+
self.policy = policy
|
|
41
|
+
self.optdefs = optdefs
|
|
42
|
+
self._initialized = True
|
|
43
|
+
|
|
44
|
+
def _kw_to_opts(self, kw):
|
|
45
|
+
res = ""
|
|
46
|
+
for k, v in kw.items():
|
|
47
|
+
if k in self.params: # skip conversion of parameters to argspec
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
res += ' '
|
|
51
|
+
flag = ('-' if len(k) == 1 else '--') + k.replace('_', '-')
|
|
52
|
+
|
|
53
|
+
if isinstance(v, bool):
|
|
54
|
+
if v:
|
|
55
|
+
res += flag
|
|
56
|
+
else:
|
|
57
|
+
if self.policy['negative_bool'] == 'prefix':
|
|
58
|
+
res += '--no-' + flag.lstrip('-')
|
|
59
|
+
|
|
60
|
+
elif isinstance(v, (list, tuple)) and v:
|
|
61
|
+
res += flag + '=' + self.policy['list_join'].join(str(item) for item in v)
|
|
62
|
+
|
|
63
|
+
elif isinstance(v, str):
|
|
64
|
+
res += flag + '="%s"' % v
|
|
65
|
+
|
|
66
|
+
else:
|
|
67
|
+
res += flag + '=' + str(v)
|
|
68
|
+
|
|
69
|
+
return res
|
|
70
|
+
|
|
71
|
+
def __call__(self, ctx=None, *args, **kwargs):
|
|
72
|
+
self._initialize()
|
|
73
|
+
if ctx is not None and not isinstance(ctx, invoke.Context):
|
|
74
|
+
# we've been passed a real argument in position 0
|
|
75
|
+
args = (ctx,) + args
|
|
76
|
+
ctx = None
|
|
77
|
+
|
|
78
|
+
kwargs['opts'] = self._kw_to_opts(kwargs)
|
|
79
|
+
posargs = ' '.join(args)
|
|
80
|
+
if 'pos' in self.params:
|
|
81
|
+
kwargs['pos'] = posargs
|
|
82
|
+
fparams = fmt(self.argspec, kwargs)
|
|
83
|
+
if 'pos' not in self.params:
|
|
84
|
+
# if placement of positional args is not specified, then put at end
|
|
85
|
+
fparams += " " + posargs
|
|
86
|
+
if ctx is None:
|
|
87
|
+
ctx = invoke.Context()
|
|
88
|
+
|
|
89
|
+
cmd = '"%s"' % self.cmd if ' ' in self.cmd else self.cmd
|
|
90
|
+
cmd += ' ' + self.required_params + fparams
|
|
91
|
+
ctx.run(cmd, warn=True)
|
|
92
|
+
return cmd
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
tree = Command('tree -I ".git|*.pyc|*.swp|dist|*.egg-info|_static|_build|_templates"')
|
dktasklib/concat.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from dkfileutils.path import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def line_endings(fname):
|
|
8
|
+
"""Return all line endings in the file.
|
|
9
|
+
"""
|
|
10
|
+
_endings = {line[-2:] for line in open(fname, 'rb').readlines()}
|
|
11
|
+
res = set()
|
|
12
|
+
for e in _endings:
|
|
13
|
+
if e.endswith(b'\r'):
|
|
14
|
+
res.add(b'\r')
|
|
15
|
+
elif e.endswith(b'\r\n'):
|
|
16
|
+
res.add(b'\r\n')
|
|
17
|
+
elif e.endswith(b'\n'):
|
|
18
|
+
res.add(b'\n')
|
|
19
|
+
return res
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def chomp(s):
|
|
23
|
+
"""Remove line terminator if it exists.
|
|
24
|
+
"""
|
|
25
|
+
if s[-2:] == b'\r\n':
|
|
26
|
+
return s[:-2]
|
|
27
|
+
if s[-1:] == b'\r' or s[-1:] == b'\n':
|
|
28
|
+
return s[:-1]
|
|
29
|
+
return s
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def fix_line_endings(fname, eol=b'\n'):
|
|
33
|
+
"""Change all line endings to ``eol``.
|
|
34
|
+
"""
|
|
35
|
+
lines = [chomp(line) for line in open(fname, 'rb').readlines()]
|
|
36
|
+
with open(fname, 'wb') as fp:
|
|
37
|
+
for line in lines:
|
|
38
|
+
fp.write(line + eol)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def copy(ctx, source, dest, force=False):
|
|
42
|
+
"""Copy ``source`` to ``dest``, which can be a file or directory.
|
|
43
|
+
"""
|
|
44
|
+
if source == dest:
|
|
45
|
+
return dest
|
|
46
|
+
|
|
47
|
+
source = os.path.normcase(os.path.normpath(str(source)))
|
|
48
|
+
dest = os.path.normcase(os.path.normpath(str(dest)))
|
|
49
|
+
flags = ""
|
|
50
|
+
if sys.platform == 'win32':
|
|
51
|
+
if force:
|
|
52
|
+
flags += " /Y"
|
|
53
|
+
ctx.run('copy {flags} {source} {dest}'.format(**locals()))
|
|
54
|
+
else: # pragma: nocover
|
|
55
|
+
if force:
|
|
56
|
+
flags += " --force"
|
|
57
|
+
ctx.run('cp {flags} {source} {dest}'.format(**locals()))
|
|
58
|
+
return dest
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def concat(ctx, dest, *sources, **kw):
|
|
62
|
+
force = kw.pop('force', False) # noqa
|
|
63
|
+
placement = Path(dest).dirname()
|
|
64
|
+
placement.makedirs()
|
|
65
|
+
|
|
66
|
+
with open(dest, 'w') as out:
|
|
67
|
+
print("Opened:", dest, "for writing.")
|
|
68
|
+
for s in sources:
|
|
69
|
+
with open(s, 'r') as inp:
|
|
70
|
+
print(" appending:", s)
|
|
71
|
+
out.writelines(inp.readlines())
|
|
72
|
+
out.write('\n')
|
|
73
|
+
|
|
74
|
+
fix_line_endings(dest)
|
|
75
|
+
|
|
76
|
+
return dest
|
dktasklib/docs.py
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import textwrap
|
|
5
|
+
import webbrowser
|
|
6
|
+
from os.path import join
|
|
7
|
+
|
|
8
|
+
from dkfileutils.changed import changed
|
|
9
|
+
from dkfileutils.path import Path
|
|
10
|
+
|
|
11
|
+
from dktasklib.entry_points.pytemplate import PyTemplate
|
|
12
|
+
from dktasklib.runners import run
|
|
13
|
+
from dktasklib.wintask import task
|
|
14
|
+
from invoke import Collection
|
|
15
|
+
|
|
16
|
+
from dktasklib import concat
|
|
17
|
+
from dktasklib import Package
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
DIRNAME = Path(__file__).dirname()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@task(name='clean')
|
|
24
|
+
def _clean(ctx): # Underscored func name to avoid shadowing kwargs in build()
|
|
25
|
+
"""Nuke docs build target directory so next build is clean.
|
|
26
|
+
"""
|
|
27
|
+
if 'pkg' not in ctx:
|
|
28
|
+
ctx.pkg = Package()
|
|
29
|
+
builddir = ctx.pkg.root / 'build' / 'docs'
|
|
30
|
+
if os.path.exists(builddir) and len(os.listdir(builddir)) > 0:
|
|
31
|
+
ctx.run("rm -rf {0}/*".format(builddir))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Ditto
|
|
35
|
+
@task(name='browse')
|
|
36
|
+
def _browse(ctx): # pragma: nocover
|
|
37
|
+
"""Open build target's index.html in a browser (using the :py:mod:`webbrowser` module).
|
|
38
|
+
"""
|
|
39
|
+
index = join(ctx.pkg.root / 'build' / 'docs' / 'index.html')
|
|
40
|
+
webbrowser.open_new(index)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@task(help=dict(
|
|
44
|
+
author='full name of author',
|
|
45
|
+
language='two letter language code (en, no, etc.)',
|
|
46
|
+
|
|
47
|
+
))
|
|
48
|
+
def initdocs(ctx, author, language):
|
|
49
|
+
"""Run sphinx-quickstart to create an initial docs folder.
|
|
50
|
+
"""
|
|
51
|
+
pkg = Package()
|
|
52
|
+
cmd = (
|
|
53
|
+
'sphinx-quickstart '
|
|
54
|
+
' --dot _'
|
|
55
|
+
' -a "{author}"'
|
|
56
|
+
' -l {language}'
|
|
57
|
+
' -v {pkg.version}'
|
|
58
|
+
' -r {pkg.version}'
|
|
59
|
+
' -p {pkg.name}'
|
|
60
|
+
' --no-makefile'
|
|
61
|
+
' --no-batchfile'
|
|
62
|
+
' --ext-autodoc'
|
|
63
|
+
' --ext-intersphinx'
|
|
64
|
+
' --ext-todo'
|
|
65
|
+
' --ext-viewcode'
|
|
66
|
+
' --suffix=".rst"'
|
|
67
|
+
' --master="index"'
|
|
68
|
+
' {docsdir}'
|
|
69
|
+
).format(
|
|
70
|
+
pkg=pkg,
|
|
71
|
+
docsdir=pkg.docs.relpath(pkg.root),
|
|
72
|
+
author=author,
|
|
73
|
+
language=language,
|
|
74
|
+
)
|
|
75
|
+
print("""
|
|
76
|
+
|
|
77
|
+
invoke can't run this command on windows..
|
|
78
|
+
|
|
79
|
+
{cmd}
|
|
80
|
+
""".format(cmd=cmd))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@task
|
|
84
|
+
def create_docs_directory(ctx, force=False):
|
|
85
|
+
"""Create docs/conf.py
|
|
86
|
+
"""
|
|
87
|
+
cwd = Path.curdir() # noqa
|
|
88
|
+
ctx.pkg.docs = ctx.pkg.docs
|
|
89
|
+
if ctx.pkg.docs.exists() and not force:
|
|
90
|
+
print("docs directory exists (use --force to overwrite)")
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
ctx.pkg.docs.makedirs()
|
|
93
|
+
ctx.pkg.docs.makedirs('_static')
|
|
94
|
+
ctx.pkg.docs.makedirs('_templates')
|
|
95
|
+
confbase = DIRNAME / 'entry_points/confbase.py'
|
|
96
|
+
txt = confbase.read('rb')
|
|
97
|
+
txt = txt.replace(b'\r\n', b'\n')
|
|
98
|
+
t = PyTemplate(txt)
|
|
99
|
+
|
|
100
|
+
(ctx.pkg.docs / 'conf.py').write(t.substitute(
|
|
101
|
+
VERSION=ctx.pkg.version,
|
|
102
|
+
PACKAGE=ctx.pkg.name,
|
|
103
|
+
YEAR=datetime.date.today().year,
|
|
104
|
+
AUTHOR=run('python setup.py --author').strip()
|
|
105
|
+
))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@task
|
|
109
|
+
def create_index(ctx, force=False):
|
|
110
|
+
"""Create docs/index.rst
|
|
111
|
+
"""
|
|
112
|
+
index = ctx.pkg.docs / 'index.rst'
|
|
113
|
+
if index.exists() and not force:
|
|
114
|
+
print("docs/index.rst exists (use --force to overwrite)")
|
|
115
|
+
sys.exit(1)
|
|
116
|
+
confbase = DIRNAME / 'entry_points/index.rst'
|
|
117
|
+
txt = confbase.read('rb')
|
|
118
|
+
txt = txt.replace(b'\r\n', b'\n')
|
|
119
|
+
t = PyTemplate(txt)
|
|
120
|
+
|
|
121
|
+
index.write(t.substitute(
|
|
122
|
+
PACKAGE=ctx.pkg.name,
|
|
123
|
+
SOURCEDIR=ctx.pkg.source,
|
|
124
|
+
))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@task
|
|
128
|
+
def make_api_docs(ctx, prefix='', force=False):
|
|
129
|
+
"""Run sphinx-apidoc to write autodoc documentation to `docs/api/*`
|
|
130
|
+
"""
|
|
131
|
+
ctx.run("rm -rf {pkg.docs}/api".format(pkg=ctx.pkg))
|
|
132
|
+
ctx.run("sphinx-apidoc -o {pkg.docs}/api {pkg.source} {pkg.source}/migrations {pkg.source}/models {pkg.source}/models.py".format(pkg=ctx.pkg))
|
|
133
|
+
if prefix:
|
|
134
|
+
for fname in (ctx.pkg.docs / 'api').glob('*.rst'):
|
|
135
|
+
f = Path(fname)
|
|
136
|
+
lines = f.read().split('\n')
|
|
137
|
+
for i, line in enumerate(lines):
|
|
138
|
+
lines[i] = line.replace(ctx.pkg.name, prefix + ctx.pkg.name)
|
|
139
|
+
if i > 0 and len(set(line)) == 1 and len(line) < len(lines[i-1]):
|
|
140
|
+
lines[i] = line[0] * len(lines[i-1])
|
|
141
|
+
f.write('\n'.join(lines))
|
|
142
|
+
pre, pkgname, post = fname.rpartition(ctx.pkg.name)
|
|
143
|
+
if pkgname and os.path.sep not in post:
|
|
144
|
+
f.rename(pre + prefix + pkgname + post)
|
|
145
|
+
|
|
146
|
+
concat.copy(ctx, ctx.pkg.docs / 'api' / '*', ctx.pkg.docs)
|
|
147
|
+
ctx.run("rm -rf {pkg.docs}/api".format(pkg=ctx.pkg))
|
|
148
|
+
|
|
149
|
+
if ".. include:: modules.rst" not in open(ctx.pkg.docs / 'index.rst').read():
|
|
150
|
+
print(textwrap.dedent("""\
|
|
151
|
+
WARNING: you need to include the following in docs/index.rst
|
|
152
|
+
|
|
153
|
+
.. include:: modules.rst
|
|
154
|
+
|
|
155
|
+
"""))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@task(default=True, help={
|
|
159
|
+
'opts': "Extra sphinx-build options/args",
|
|
160
|
+
'prefix': "Module prefix, for submodules",
|
|
161
|
+
'clean': "Remove build tree before building",
|
|
162
|
+
'browse': "Open docs index in browser after building",
|
|
163
|
+
'warn': "Build with stricter warnings/errors enabled",
|
|
164
|
+
'builder': "Builder to use, defaults to html",
|
|
165
|
+
'force': "Force re-reading of all files (ignore cache)",
|
|
166
|
+
})
|
|
167
|
+
def build(ctx, clean=False, browse=False, warn=False,
|
|
168
|
+
builder='html',
|
|
169
|
+
force=False,
|
|
170
|
+
opts="", prefix=''):
|
|
171
|
+
"""
|
|
172
|
+
Build the project's Sphinx docs.
|
|
173
|
+
"""
|
|
174
|
+
if not force and not changed(ctx.pkg.docs):
|
|
175
|
+
print("""
|
|
176
|
+
No changes detected in {}, add --force to build docs anyway.
|
|
177
|
+
""".format(ctx.pkg.docs))
|
|
178
|
+
return # should perhaps check if code has changed too? (autodoc)
|
|
179
|
+
|
|
180
|
+
if clean:
|
|
181
|
+
_clean(ctx)
|
|
182
|
+
make_api_docs(ctx, force=force, prefix=prefix)
|
|
183
|
+
|
|
184
|
+
if opts is None: # pragma: nocover
|
|
185
|
+
opts = ""
|
|
186
|
+
opts += " -b %s" % builder
|
|
187
|
+
if warn:
|
|
188
|
+
opts += " -n -W"
|
|
189
|
+
if force:
|
|
190
|
+
opts += " -a -E"
|
|
191
|
+
cmd = "sphinx-build {opts} {ctx.pkg.docs} {ctx.pkg.root}/build/docs".format(opts=opts, ctx=ctx)
|
|
192
|
+
dj_settings = ctx.pkg.get('django_settings_module', "")
|
|
193
|
+
if dj_settings:
|
|
194
|
+
os.environ['DJANGO_SETTINGS_MODULE'] = dj_settings
|
|
195
|
+
ctx.run(cmd)
|
|
196
|
+
if browse: # pragma: nocover
|
|
197
|
+
_browse(ctx)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@task
|
|
201
|
+
def tree(ctx):
|
|
202
|
+
"""Display the docs tree.
|
|
203
|
+
"""
|
|
204
|
+
ignore = ".git|*.pyc|*.swp|dist|*.egg-info|_static|_build|_templates"
|
|
205
|
+
ctx.run('tree -Ca -I "{0}" {1}'.format(ignore, ctx.pkg.docs))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# Vanilla/default/parameterized collection for normal use
|
|
209
|
+
ns = Collection(
|
|
210
|
+
'docs',
|
|
211
|
+
_clean,
|
|
212
|
+
_browse,
|
|
213
|
+
build,
|
|
214
|
+
tree,
|
|
215
|
+
initdocs,
|
|
216
|
+
create_docs_directory,
|
|
217
|
+
create_index,
|
|
218
|
+
)
|
|
219
|
+
ns.configure({
|
|
220
|
+
'docs': {
|
|
221
|
+
'source': 'docs',
|
|
222
|
+
'builddir': join('build', 'docs'),
|
|
223
|
+
'target_file': 'index.html',
|
|
224
|
+
}
|
|
225
|
+
})
|