Skip to content

Commit

Permalink
Allow files not to be created during an update
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianWilhelm committed May 28, 2015
1 parent 1ef0a90 commit 8e439fa
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 79 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Version 2.2, 2015-??-??
- Improved default README.rst, issue #51
- Use tests/conftest.py instead of tests/__init__.py, issue #52
- Use setuptools_scm for versioning, issue #43
- Require setuptools>=9.0, issue #56
- Do not create skeleton.py during an update, issue #55

.. note::

Expand Down
101 changes: 46 additions & 55 deletions pyscaffold/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@
__license__ = "new BSD"


class FileOp(object):
"""
Namespace for file operations during an update
NO_OVERWRITE: Do not overwrite an existing file during update
NO_CREATE: Do not create the file during an update
"""
NO_OVERWRITE = 0
NO_CREATE = 1


def set_default_args(args):
"""
Set default arguments for some parameters
Expand Down Expand Up @@ -114,26 +125,25 @@ def make_structure(args):
if args.tox:
proj_dir["tox.ini"] = templates.tox(args)
if args.update and not args.force: # Do not overwrite following files
safe = {args.project: {
".gitignore": None,
".gitattributes": None,
"setup.cfg": None,
"README.rst": None,
"CHANGES.rst": None,
"LICENSE.txt": None,
"AUTHORS.rst": None,
"requirements.txt": None,
".travis.yml": None,
".coveragerc": None,
".pre-commit-config.yaml": None,
"tox.ini": None,
args.package: {"skeleton.py": None},
"tests": {"conftest.py": None,
"travis_install.sh": None},
"docs": {"index.rst": None}
rules = {args.project: {
".gitignore": FileOp.NO_OVERWRITE,
".gitattributes": FileOp.NO_OVERWRITE,
"setup.cfg": FileOp.NO_OVERWRITE,
"README.rst": FileOp.NO_OVERWRITE,
"CHANGES.rst": FileOp.NO_OVERWRITE,
"LICENSE.txt": FileOp.NO_OVERWRITE,
"AUTHORS.rst": FileOp.NO_OVERWRITE,
"requirements.txt": FileOp.NO_OVERWRITE,
".travis.yml": FileOp.NO_OVERWRITE,
".coveragerc": FileOp.NO_OVERWRITE,
".pre-commit-config.yaml": FileOp.NO_OVERWRITE,
"tox.ini": FileOp.NO_OVERWRITE,
args.package: {"skeleton.py": FileOp.NO_CREATE},
"tests": {"conftest.py": FileOp.NO_OVERWRITE,
"travis_install.sh": FileOp.NO_OVERWRITE},
"docs": {"index.rst": FileOp.NO_OVERWRITE}
}}
safe = check_files_exist(safe)
struct = remove_from_struct(struct, safe)
struct = apply_update_rules(rules, struct)
struct = add_namespace(args, struct)

return struct
Expand Down Expand Up @@ -186,6 +196,11 @@ def create_django_proj(args):


def create_cookiecutter(args):
"""
Create a cookie cutter template
:param args: command line parameters as :obj:`argparse.Namespace`
"""
try:
from cookiecutter.main import cookiecutter
except:
Expand All @@ -206,50 +221,26 @@ def create_cookiecutter(args):
args.force = True


def check_files_exist(struct, prefix=None):
def apply_update_rules(rules, struct, prefix=None):
"""
Checks which files exist in a directory structure
Apply update rules using :obj:`~.FileOp` to a directory structure
:param rules: directory structure as dictionary of dictionaries with
:obj:`~.FileOp` keys. The structure will be modified.
:param struct: directory structure as dictionary of dictionaries
:param prefix: prefix path for the structure
:return: returns a dictionary of dictionaries where keys representing
files exists in the filesystem.
"""
result = dict()
if prefix is None:
prefix = os.getcwd()
for name, content in struct.items():
if isinstance(content, dict):
result[name] = check_files_exist(struct[name],
prefix=join_path(prefix, name))
if not result[name]: # dict is empty
del result[name]
else:
if os.path.isfile(join_path(prefix, name)):
result[name] = content
return result


def remove_from_struct(orig_struct, del_struct):
"""
Removes files existing in `del_struct` from structure `orig_struct`
:param orig_struct: directory structure as dictionary of dictionaries
:param del_struct: directory structure as dictionary of dictionaries
:return: directory structure as dictionary of dictionaries
"""
result = dict()
for k, v in orig_struct.items():
for k, v in rules.items():
if isinstance(v, dict):
if k in del_struct:
result[k] = remove_from_struct(orig_struct[k], del_struct[k])
if not result[k]: # dict is empty
del result[k]
else:
result[k] = copy.deepcopy(orig_struct[k])
apply_update_rules(v, struct[k], join_path(prefix, k))
else:
if k in del_struct:
continue
else:
result[k] = orig_struct[k]
return result
path = join_path(prefix, k)
if v == FileOp.NO_OVERWRITE and os.path.exists(path):
struct.pop(k, None)
elif v == FileOp.NO_CREATE:
struct.pop(k, None)
return struct
48 changes: 24 additions & 24 deletions tests/test_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,31 +104,31 @@ def test_make_structure_with_tox():
assert isinstance(struct["project"]["tox.ini"], six.string_types)


def test_check_files_exist(tmpdir): # noqa
struct = {"a": "a", "b": "b", "c": {"a": "a", "b": "b"}, "d": {"a": "a"}}
dir_struct = {"a": "a", "c": {"b": "b"}}
def test_apply_update_rules(tmpdir): # noqa
NO_OVERWRITE = structure.FileOp.NO_OVERWRITE
NO_CREATE = structure.FileOp.NO_CREATE
rules = {"a": NO_OVERWRITE,
"c": {"b": NO_OVERWRITE},
"d": {"a": NO_OVERWRITE,
"b": NO_CREATE,
"c": NO_CREATE,
"d": NO_OVERWRITE},
"e": NO_CREATE}
struct = {"a": "a",
"b": "b",
"c": {"a": "a",
"b": "b"},
"d": {"a": "a",
"b": "b"},
"e": "e"}
dir_struct = {"a": "a",
"c": {"b": "b"}}
exp_struct = {"b": "b",
"c": {"a": "a"},
"d": {"a": "a"}}
structure.create_structure(dir_struct)
res = structure.check_files_exist(struct)
assert res == dir_struct


def test_remove_from_struct():
orig_struct = {"a": 1, "b": 2, "c": 3}
del_struct = {"a": 1}
res = structure.remove_from_struct(orig_struct, del_struct)
assert res == {"b": 2, "c": 3}
orig_struct = {"a": 1, "b": 2, "c": {"a": 1}}
del_struct = {"a": 1}
res = structure.remove_from_struct(orig_struct, del_struct)
assert res == {"b": 2, "c": {"a": 1}}
orig_struct = {"a": 1, "b": 2, "c": {"a": 1}}
del_struct = {"c": {"a": 1}}
res = structure.remove_from_struct(orig_struct, del_struct)
assert res == {"a": 1, "b": 2}
orig_struct = {"a": 1, "b": 2, "c": {"a": 1, "b": 2}}
del_struct = {"a": 1, "c": {"a": 1}}
res = structure.remove_from_struct(orig_struct, del_struct)
assert res == {"b": 2, "c": {"b": 2}}
res_struct = structure.apply_update_rules(rules, struct)
assert res_struct == exp_struct


def test_add_namespace():
Expand Down

0 comments on commit 8e439fa

Please sign in to comment.