diff --git a/README.fr-FR.md b/README.fr-FR.md index ce8ba3b..1e6e831 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -118,16 +118,24 @@ Ces modules sont listés au démarrage de Jean-Paul Start, s'ils répondent aux ### Copy -Permet de copier un fichier +Permet de copier un fichier ou un dossier -Si la destination existe, et `force: no`, aucune action n'est effectuée +Si le chemin est un dossier, il est copié recursivement. Dans ce cas, si le chemin se termine par "/", seul le contenu de ce dossier sera copié vers la destination. + +Si la source est un dossier, la destination doit etre un dossier aussi. + +Si la destination existe, et `force: no`, aucune action n'est effectuée. + +- `force` est facultatif, sa valeur par défaut est `yes` +- `replace` est facultatif, sa valeur par défaut est `no` ````yaml - name: Name of task copy: - src: /path/to/source.ext - dest: /path/to/destination.ext + src: /path/to/source + dest: /path/to/destination force: [yes|no] + replace: [yes|no] ```` ### File diff --git a/README.md b/README.md index 3031daa..5a4a3fb 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ _Hell is the .bats_ ## Installation ````bash -pip install git+https://github.com/Arubinu/jeanpaulstart.git +pip install git+https://github.com/cube-creative/jeanpaulstart.git ```` ## Usage as a CLI @@ -131,16 +131,24 @@ Tasks are written as plugins, in the package `jeanpaulstart.tasks`, they must co ### Copy -Copies a file +Copies a file or a directory -If destination exists and `force: no`, nothing will happen +If path is a directory, it is copied recursively. In this case, if path ends with "/", only inside contents of that directory are copied to destination. + +If the source is a directory, the destination must be a directory too. + +If destination exists and `force: no`, nothing will happen. + +- `force` is not mandatory, defaults to `yes` +- `replace` is not mandatory, defaults to `no` ````yaml - name: Name of task copy: - src: /path/to/source.ext - dest: /path/to/destination.ext + src: /path/to/source + dest: /path/to/destination force: [yes|no] + replace: [yes|no] ```` ### File diff --git a/jeanpaulstart/file_io.py b/jeanpaulstart/file_io.py index aadcdff..07dd2a0 100644 --- a/jeanpaulstart/file_io.py +++ b/jeanpaulstart/file_io.py @@ -1,6 +1,7 @@ import os import io import shutil +import distutils.dir_util def read_file_utf16(filepath): @@ -12,14 +13,40 @@ def read_file_utf16(filepath): return f.read() -def copy(source, destination, force=True): - if not force and os.path.isfile(destination): +def copy(source, destination, force=True, replace=False): + if not force and os.path.exists(destination): return - dirname = os.path.dirname(destination) - if not os.path.isdir(dirname): os.makedirs(dirname) - - shutil.copy(source, destination) + # If source is a directory, the destination must be a directory too and + # if the destination exists, is a file, an exception is raised. + if os.path.isdir(source) and os.path.isfile(destination): + raise ValueError('The destination must be a directory') + + # If destination is a non-existent path and if either destination ends + # with "/" or source is a directory, destination is created. + if not os.path.exists(destination): + if destination.endswith('/') or os.path.isdir(source): + os.makedirs(destination) + + # If the source is a file and the destination dirname is a non-existent + # path, dirname is created. + if os.path.isfile(source): + dirname = os.path.dirname(destination) + if not os.path.exists(dirname): + os.makedirs(dirname) + + if os.path.isdir(source) and os.path.isdir(destination): + if not destination.endswith('/'): + name = os.path.split(source)[-1] + destination = os.path.join(destination, name) + + # Clear + if replace: + shutil.rmtree(destination) + + shutil.copytree(source, destination, dirs_exist_ok=True) + else: + shutil.copy(source, destination) def mkdir(path): diff --git a/jeanpaulstart/tasks/copy_.py b/jeanpaulstart/tasks/copy_.py index d727db8..1b9d0fa 100644 --- a/jeanpaulstart/tasks/copy_.py +++ b/jeanpaulstart/tasks/copy_.py @@ -11,10 +11,11 @@ def validate(user_data): def normalize_after_split(splitted): splitted['arguments']['force'] = splitted['arguments'].get('force', True) + splitted['arguments']['replace'] = splitted['arguments'].get('replace', False) return splitted -def apply_(src, dest, force): - file_io.copy(src, dest, force) +def apply_(src, dest, force, replace): + file_io.copy(src, dest, force, replace) return OK diff --git a/jeanpaulstart/tasks/delete_.py b/jeanpaulstart/tasks/delete_.py new file mode 100644 index 0000000..127d999 --- /dev/null +++ b/jeanpaulstart/tasks/delete_.py @@ -0,0 +1,37 @@ +import os +import shutil +from jeanpaulstart.constants import * + + +TASK_COMMAND = 'delete' + + +def validate(user_data): + return OK, "" + + +def normalize_after_split(splitted): + return splitted + + +def apply_(path): + if not os.path.exists(path): + return OK + + if os.path.isdir(path): + if path[-1] in ("/", "\\"): # Delete content + for filename in os.listdir(path): + file_path = os.path.join(path, filename) + + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + os.system('rmdir /S /Q "{}"'.format(file_path)) + # shutil.rmtree(file_path) + else: # Delete whole directory + os.system('rmdir /S /Q "{}"'.format(path)) + # shutil.rmtree(path) + else: + os.remove(path) + + return OK diff --git a/jeanpaulstart/tasks/git_.py b/jeanpaulstart/tasks/git_.py new file mode 100644 index 0000000..a7fc57a --- /dev/null +++ b/jeanpaulstart/tasks/git_.py @@ -0,0 +1,41 @@ +import git +import os +from string import Template +from jeanpaulstart.constants import * + +TASK_COMMAND = 'git' +DEFAULT_BRANCH = 'master' + + +def validate(user_data): + return OK, "" + + +def normalize_after_split(splitted): + splitted['arguments']['branch'] = splitted['arguments'].get('branch', DEFAULT_BRANCH) + return splitted + + +def apply_(url, dest, branch): + checkout_remote(url, dest, branch) + + return OK + + +def checkout_remote(url, dest, branch): + dest = Template(dest).substitute(os.environ) + parent = os.path.abspath(os.path.join(dest, os.pardir)) + if not os.path.exists(parent): + os.makedirs(parent) + + if not os.path.exists(dest): + repo = git.Repo.clone_from(url, dest) + else: + repo = git.Repo(dest) + + repo.git.fetch("--all") + repo.git.reset("--hard", "origin/{}".format(branch)) + repo.git.clean("-dfx") + repo.git.fetch("--all") + repo.git.pull("origin", branch, "--tags", "--no-edit") + repo.git.checkout("-B", branch, "origin/{}".format(branch)) diff --git a/jeanpaulstart/tasks/line_in_file.py b/jeanpaulstart/tasks/line_in_file.py new file mode 100644 index 0000000..9afe8dd --- /dev/null +++ b/jeanpaulstart/tasks/line_in_file.py @@ -0,0 +1,44 @@ +from jeanpaulstart.constants import * + + +TASK_COMMAND = 'line_in_file' + + +def validate(user_data): + return OK, "" + + +def normalize_after_split(splitted): + splitted['arguments']['replace'] = splitted['arguments'].get('replace', False) + return splitted + + +def apply_(filepath, value, insert_after, replace): + insert_line(filepath, value, insert_after, replace) + + return OK + + +def insert_line(filepath, value, insert_after, replace): + value += "\n" + with open(filepath) as f: + content = f.readlines() + + if insert_after: + row = None + for index, line in enumerate(content): + if line == insert_after + '\n': + row = index + 1 + break + else: + row = 0 + + if content[row] == value and not replace: + return + + if row is not None: + content.insert(row, value) + + with open(filepath, 'w') as f: + for line in content: + f.write(line)