Skip to content

Commit

Permalink
Merge branch 'use-rsync'
Browse files Browse the repository at this point in the history
  • Loading branch information
ento committed Mar 12, 2019
2 parents 6257033 + 97f5dae commit 17c8274
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 21 deletions.
1 change: 0 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ doit = "*"
retrying = "*"
typing = "*"
attrs = "*"
dirsync = "*"
parsy = "*"
requests = "*"

Expand Down
21 changes: 7 additions & 14 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Generate static documentation of your Elm application project.

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

Supported Elm versions:

Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
install_requires=[
'attrs',
'click',
'dirsync',
'doit',
'parsy',
'requests',
Expand Down
25 changes: 25 additions & 0 deletions src/elm_doc/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import os
import os.path
import shutil
import subprocess
from pathlib import Path
import functools
import re

import click
from doit.doit_cmd import DoitMain
Expand Down Expand Up @@ -41,6 +43,22 @@ def validate_elm_path(ctx, param, value):
return value


REQUIRED_RSYNC_VERSION = (2, 6, 7)


def check_rsync_version() -> bool:
output = subprocess.check_output(['rsync', '--version'], universal_newlines=True)
first_line = output.splitlines()[0]
match = re.search(r'version (?P<major>\d)\.(?P<minor>\d)\.(?P<patch>\d)', first_line)
if not match:
raise click.Abort(
'could not extract the version of rsync from: {}'.format(first_line))
version = (int(match.group('major')),
int(match.group('minor')),
int(match.group('patch')))
return version >= REQUIRED_RSYNC_VERSION


def _resolve_path(path: str) -> Path:
# not using Path.resolve() for now because we don't expect strict
# existence checking. maybe we should.
Expand Down Expand Up @@ -141,6 +159,13 @@ def main(
include_paths):
"""Generate static documentation for your Elm project"""

if not shutil.which('rsync'):
raise click.UsageError('this program requires rsync')

if not check_rsync_version():
raise click.UsageError('this program requires rsync version {} or greater'
.format('.'.join(REQUIRED_RSYNC_VERSION)))

if not validate and output is None:
raise click.BadParameter('please specify --output directory')

Expand Down
24 changes: 20 additions & 4 deletions src/elm_doc/project_tasks.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import List, Optional
from collections import ChainMap
import os.path
from pathlib import Path
from collections import ChainMap
import json
from tempfile import TemporaryDirectory
import subprocess

from dirsync import sync
from doit.tools import create_folder, config_changed

from elm_doc import elm_platform
Expand Down Expand Up @@ -39,8 +39,7 @@ def build_project_docs_json(
json.dump(elm_project_with_exposed_modules, f)

package_src_dir = build_path / 'src'
for source_dir in project.source_directories:
sync(str(project.path / source_dir), str(package_src_dir), 'sync', create=True)
_sync_source_files(project, package_src_dir)

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


@capture_subprocess_error_as_task_failure
def _sync_source_files(project: ElmProject, target_directory: Path) -> None:
'''Copy source files to a single directory. This meets the requirement of Elm
that a package project can only have a single source directory and gives
us an isolated environment so that Elm can run in parallel with any invocation
of Elm within the actual project.
'''
target_directory.mkdir(parents=True, exist_ok=True)
sources = ['{}/./'.format(os.path.normpath(source_dir))
for source_dir in project.source_directories]
subprocess.check_output(
['rsync', '-a', '--delete', '--recursive'] + sources + [str(target_directory)],
cwd=str(project.path),
stderr=subprocess.STDOUT,
)


def create_main_project_tasks(
project: ElmProject,
project_config: ProjectConfig,
Expand Down
68 changes: 68 additions & 0 deletions tests/test_project_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from pathlib import Path

from elm_doc import elm_project
from elm_doc import project_tasks


def test_sync_source_files_create_new_file(
tmpdir, elm_version, make_elm_project):
project_dir = make_elm_project(
elm_version,
tmpdir,
sources={
'src': [
'Main.elm',
],
},
copy_elm_stuff=False,
)
project = elm_project.from_path(Path(str(project_dir)))
target_dir = Path(str(project_dir / 'tmp'))
project_tasks._sync_source_files(project, target_dir)
assert (target_dir / 'Main.elm').exists()


def test_sync_source_files_update_file(
tmpdir, elm_version, make_elm_project):
project_dir = make_elm_project(
elm_version,
tmpdir,
sources={
'src': [
'Main.elm',
],
},
copy_elm_stuff=False,
)
project = elm_project.from_path(Path(str(project_dir)))
target_dir = Path(str(project_dir / 'tmp'))
project_tasks._sync_source_files(project, target_dir)

main_elm = project_dir.join('src', 'Main.elm')
main_elm.write('updated for testing')

project_tasks._sync_source_files(project, target_dir)
assert (target_dir / 'Main.elm').read_text() == 'updated for testing'


def test_sync_source_files_delete_file(
tmpdir, elm_version, make_elm_project):
project_dir = make_elm_project(
elm_version,
tmpdir,
sources={
'src': [
'Main.elm',
],
},
copy_elm_stuff=False,
)
project = elm_project.from_path(Path(str(project_dir)))
target_dir = Path(str(project_dir / 'tmp'))
project_tasks._sync_source_files(project, target_dir)

main_elm = project_dir.join('src', 'Main.elm')
main_elm.remove()

project_tasks._sync_source_files(project, target_dir)
assert not (target_dir / 'Main.elm').exists()

0 comments on commit 17c8274

Please sign in to comment.