Skip to content

Commit 17c8274

Browse files
committed
Merge branch 'use-rsync'
2 parents 6257033 + 97f5dae commit 17c8274

7 files changed

Lines changed: 121 additions & 21 deletions

File tree

Pipfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ doit = "*"
99
retrying = "*"
1010
typing = "*"
1111
attrs = "*"
12-
dirsync = "*"
1312
parsy = "*"
1413
requests = "*"
1514

Pipfile.lock

Lines changed: 7 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Generate static documentation of your Elm application project.
44

5-
Requires Python >= 3.5, and macOS or Linux. It may work on Windows but it's untested.
5+
Requires Python >= 3.5, rsync >= 2.6.7, and macOS or Linux. It may work on Windows but it's untested.
66

77
Supported Elm versions:
88

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
install_requires=[
2020
'attrs',
2121
'click',
22-
'dirsync',
2322
'doit',
2423
'parsy',
2524
'requests',

src/elm_doc/cli.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
import os
33
import os.path
44
import shutil
5+
import subprocess
56
from pathlib import Path
67
import functools
8+
import re
79

810
import click
911
from doit.doit_cmd import DoitMain
@@ -41,6 +43,22 @@ def validate_elm_path(ctx, param, value):
4143
return value
4244

4345

46+
REQUIRED_RSYNC_VERSION = (2, 6, 7)
47+
48+
49+
def check_rsync_version() -> bool:
50+
output = subprocess.check_output(['rsync', '--version'], universal_newlines=True)
51+
first_line = output.splitlines()[0]
52+
match = re.search(r'version (?P<major>\d)\.(?P<minor>\d)\.(?P<patch>\d)', first_line)
53+
if not match:
54+
raise click.Abort(
55+
'could not extract the version of rsync from: {}'.format(first_line))
56+
version = (int(match.group('major')),
57+
int(match.group('minor')),
58+
int(match.group('patch')))
59+
return version >= REQUIRED_RSYNC_VERSION
60+
61+
4462
def _resolve_path(path: str) -> Path:
4563
# not using Path.resolve() for now because we don't expect strict
4664
# existence checking. maybe we should.
@@ -141,6 +159,13 @@ def main(
141159
include_paths):
142160
"""Generate static documentation for your Elm project"""
143161

162+
if not shutil.which('rsync'):
163+
raise click.UsageError('this program requires rsync')
164+
165+
if not check_rsync_version():
166+
raise click.UsageError('this program requires rsync version {} or greater'
167+
.format('.'.join(REQUIRED_RSYNC_VERSION)))
168+
144169
if not validate and output is None:
145170
raise click.BadParameter('please specify --output directory')
146171

src/elm_doc/project_tasks.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from typing import List, Optional
2-
from collections import ChainMap
2+
import os.path
33
from pathlib import Path
4+
from collections import ChainMap
45
import json
56
from tempfile import TemporaryDirectory
67
import subprocess
78

8-
from dirsync import sync
99
from doit.tools import create_folder, config_changed
1010

1111
from elm_doc import elm_platform
@@ -39,8 +39,7 @@ def build_project_docs_json(
3939
json.dump(elm_project_with_exposed_modules, f)
4040

4141
package_src_dir = build_path / 'src'
42-
for source_dir in project.source_directories:
43-
sync(str(project.path / source_dir), str(package_src_dir), 'sync', create=True)
42+
_sync_source_files(project, package_src_dir)
4443

4544
for elm_file_path in package_src_dir.glob('**/*.elm'):
4645
if elm_parser.is_port_module(elm_file_path):
@@ -65,6 +64,23 @@ def _run_elm_make(elm_path: Path, output_path: Path, build_path: Path):
6564
)
6665

6766

67+
@capture_subprocess_error_as_task_failure
68+
def _sync_source_files(project: ElmProject, target_directory: Path) -> None:
69+
'''Copy source files to a single directory. This meets the requirement of Elm
70+
that a package project can only have a single source directory and gives
71+
us an isolated environment so that Elm can run in parallel with any invocation
72+
of Elm within the actual project.
73+
'''
74+
target_directory.mkdir(parents=True, exist_ok=True)
75+
sources = ['{}/./'.format(os.path.normpath(source_dir))
76+
for source_dir in project.source_directories]
77+
subprocess.check_output(
78+
['rsync', '-a', '--delete', '--recursive'] + sources + [str(target_directory)],
79+
cwd=str(project.path),
80+
stderr=subprocess.STDOUT,
81+
)
82+
83+
6884
def create_main_project_tasks(
6985
project: ElmProject,
7086
project_config: ProjectConfig,

tests/test_project_tasks.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from pathlib import Path
2+
3+
from elm_doc import elm_project
4+
from elm_doc import project_tasks
5+
6+
7+
def test_sync_source_files_create_new_file(
8+
tmpdir, elm_version, make_elm_project):
9+
project_dir = make_elm_project(
10+
elm_version,
11+
tmpdir,
12+
sources={
13+
'src': [
14+
'Main.elm',
15+
],
16+
},
17+
copy_elm_stuff=False,
18+
)
19+
project = elm_project.from_path(Path(str(project_dir)))
20+
target_dir = Path(str(project_dir / 'tmp'))
21+
project_tasks._sync_source_files(project, target_dir)
22+
assert (target_dir / 'Main.elm').exists()
23+
24+
25+
def test_sync_source_files_update_file(
26+
tmpdir, elm_version, make_elm_project):
27+
project_dir = make_elm_project(
28+
elm_version,
29+
tmpdir,
30+
sources={
31+
'src': [
32+
'Main.elm',
33+
],
34+
},
35+
copy_elm_stuff=False,
36+
)
37+
project = elm_project.from_path(Path(str(project_dir)))
38+
target_dir = Path(str(project_dir / 'tmp'))
39+
project_tasks._sync_source_files(project, target_dir)
40+
41+
main_elm = project_dir.join('src', 'Main.elm')
42+
main_elm.write('updated for testing')
43+
44+
project_tasks._sync_source_files(project, target_dir)
45+
assert (target_dir / 'Main.elm').read_text() == 'updated for testing'
46+
47+
48+
def test_sync_source_files_delete_file(
49+
tmpdir, elm_version, make_elm_project):
50+
project_dir = make_elm_project(
51+
elm_version,
52+
tmpdir,
53+
sources={
54+
'src': [
55+
'Main.elm',
56+
],
57+
},
58+
copy_elm_stuff=False,
59+
)
60+
project = elm_project.from_path(Path(str(project_dir)))
61+
target_dir = Path(str(project_dir / 'tmp'))
62+
project_tasks._sync_source_files(project, target_dir)
63+
64+
main_elm = project_dir.join('src', 'Main.elm')
65+
main_elm.remove()
66+
67+
project_tasks._sync_source_files(project, target_dir)
68+
assert not (target_dir / 'Main.elm').exists()

0 commit comments

Comments
 (0)