Convert Blender-Purge
to a more generic Blender-Crawl
Tool
#42
54
scripts/blender-crawl/README.md
Normal file
54
scripts/blender-crawl/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# blender_crawl
|
||||
`blender_crawl` is a command line tools to crawl directories for .blend files and execute a provied script.
|
||||
## Table of Contents
|
||||
- [Prerequisite](#prerequisite)
|
||||
- [Installation](#installation)
|
||||
- [How to get started](#how-to-get-started)
|
||||
|
||||
## Prerequisite
|
||||
In order to use this tool you need:
|
||||
- Python 3.5+
|
||||
|
||||
## Run without Installation
|
||||
1. Clone this repository with `git clone https://projects.blender.org/studio/blender-studio-pipeline.git`
|
||||
2. Run `cd blender-studio-pipeline/scripts/blender-crawl` to enter directory
|
||||
3. Run program with `python blender_crawl /my-folder/`
|
||||
|
||||
## Installation
|
||||
Download or clone this repository.
|
||||
This repository is a command line tool that can be installed with the python packaging manager.
|
||||
This script does the following (follow this if you want to do this manually or on another platform):
|
||||
|
||||
1. Clone this repository with `git clone https://projects.blender.org/studio/blender-studio-pipeline.git`
|
||||
2. Run `cd blender-studio-pipeline/scripts/blender-crawl` to enter directory
|
||||
3. Install with `python setup.py install`
|
||||
4. Run with `blender_crawl /my-folder/`
|
||||
5. Get help with `blender_crawl -h`
|
||||
|
||||
|
||||
## How to get started
|
||||
Run directly out of repo folder or follow above installation instructions. Give `blender_crawl` a path to a .blend file or a folder as first argument, The detected blend files will be opened in the background, the python script will be executed, and the file closes. If blender is not installed at the default location of your computer, you need to provide a blender executable using the --exec flag.
|
||||
|
||||
| Command | Description |
|
||||
| ----------- | ----------- |
|
||||
| --script| Path to blender python script(s) to execute inside .blend files during crawl.|
|
||||
| -r, --recursive| If provided in combination with a folder path will perform recursive crawl|
|
||||
| -f --filter| Provide a string to filter the found .blend files|
|
||||
| -a, --ask| If provided there will be no confirmation prompt before running script on .blend files.|
|
||||
| -p, --purge| Run 'built-in function to purge data-blocks from all .blend files found in crawl.'.|
|
||||
| --exec| If provided user must provide blender executable path, OS default blender will not be used if found.|
|
||||
| -h, --help| show the above help message and exit|
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
| Action | Command |
|
||||
| ----------- | ----------- |
|
||||
|Prints the names of .blends in Current Directory | `blender_crawl ./` |
|
||||
|Print the names of .blends Recursively | `blender_crawl /my-folder/ --recursive` |
|
||||
|Print only the names of .blends matching a provided string |`blender_crawl /my-folder/ --find string`|
|
||||
|Run default 'Purge' script on .blends in Current Directory |`blender_crawl /my-folder/ --purge`|
|
||||
|Run custom script on all .blends in Current Directory |`blender_crawl /my-folder/ --script /my-directory/my-script.py`|
|
||||
|Ask/Prompt before script execution|`blender_crawl /my-folder/ --script /my-directory/my-script.py --ask`|
|
||||
|Run with a custom blender executable|`blender_crawl /my-folder/ --exec /path-to-blender-executable/blender`|
|
||||
|
247
scripts/blender-crawl/blender_crawl/__main__.py
Normal file
247
scripts/blender-crawl/blender_crawl/__main__.py
Normal file
@ -0,0 +1,247 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import argparse
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
# Command line arguments.
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"path",
|
||||
help="Path to a file(s) or folder(s) on which to perform crawl",
|
||||
nargs='+'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"--exec",
|
||||
help="If --exec user must provide blender executable path, OS default blender will not be used if found.",
|
||||
type=str,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--script",
|
||||
help="Path to blender python script(s) to execute inside .blend files during crawl. Execution is skipped if no script is provided",
|
||||
nargs='+',
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--recursive",
|
||||
help="If -r is provided in combination with a folder path will perform recursive crawl",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--filter",
|
||||
help="Provide a string to filter the found .blend files",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--ask",
|
||||
help="If --ask is provided there will be no confirmation prompt before running script on .blend files.",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--purge",
|
||||
help="Run 'built-in function to purge data-blocks from all .blend files found in crawl.'.",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
def cancel_program(message: str):
|
||||
print(message)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def find_executable() -> Path:
|
||||
|
||||
if os.name != 'nt':
|
||||
output = subprocess.run(
|
||||
['which', 'blender'], capture_output=True, encoding="utf-8"
|
||||
)
|
||||
if output.returncode == 0:
|
||||
# Returncode includes \n in string to indicate a new line
|
||||
return Path(output.stdout.strip('\n'))
|
||||
cancel_program("Blender Executable not found please provide --exec argument")
|
||||
|
||||
|
||||
def prompt_confirm(list_length: int):
|
||||
file_plural = "files" if list_length > 1 else "file"
|
||||
confirm_str = f"Do you want to crawl {list_length} {file_plural}? ([y]es/[n]o)"
|
||||
while True:
|
||||
user_input = input(confirm_str).lower()
|
||||
if not user_input in ["yes", "no", "y", "n"]:
|
||||
print("\nPlease enter a valid answer!")
|
||||
continue
|
||||
if user_input in ["no", "n"]:
|
||||
print("\nProcess was canceled.")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def is_filepath_blend(path: Path) -> None:
|
||||
# Check if path is file.
|
||||
if not path.is_file():
|
||||
cancel_program(f"Not a file: {path.suffix}")
|
||||
|
||||
# Check if path is blend file.
|
||||
if path.suffix != ".blend":
|
||||
cancel_program(f"Not a blend file: {path.suffix}")
|
||||
|
||||
|
||||
def check_file_exists(file_path_str: str, error_msg: str):
|
||||
if file_path_str is None:
|
||||
return
|
||||
file_path = Path(file_path_str).absolute()
|
||||
if file_path.exists():
|
||||
return file_path
|
||||
else:
|
||||
cancel_program(error_msg)
|
||||
|
||||
|
||||
def get_purge_path(purge: bool):
|
||||
# Cancel function if user has not supplied purge arg
|
||||
if not purge:
|
||||
return
|
||||
scripts_directory = Path((os.path.dirname(__file__))).joinpath("default_scripts/")
|
||||
purge_script = os.path.join(scripts_directory.resolve(), "purge.py")
|
||||
return check_file_exists(str(purge_script), "Default scripts location may be invalid")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
import sys
|
||||
"""Crawl blender files in a directory and run a provided scripts"""
|
||||
# Parse arguments.
|
||||
args = parser.parse_args()
|
||||
purge_path = get_purge_path(args.purge)
|
||||
recursive = args.recursive
|
||||
exec = args.exec
|
||||
regex = args.filter
|
||||
script_input = args.script
|
||||
ask_for_confirmation = args.ask
|
||||
|
||||
scripts = []
|
||||
if script_input:
|
||||
for script in script_input:
|
||||
script_name = check_file_exists(
|
||||
script,
|
||||
"No --script was not provided as argument, printed found .blend files, exiting program.",
|
||||
)
|
||||
scripts.append(script_name)
|
||||
|
||||
# Purge is optional so it can be none
|
||||
if purge_path is not None:
|
||||
scripts.append(purge_path)
|
||||
|
||||
if not exec:
|
||||
blender_exec = find_executable()
|
||||
else:
|
||||
blender_exec = Path(exec).absolute()
|
||||
if not blender_exec.exists():
|
||||
cancel_program("Blender Executable Path is not valid")
|
||||
|
||||
# Vars.
|
||||
files = []
|
||||
for item in args.path:
|
||||
file_path = Path(item).absolute()
|
||||
if not file_path.exists():
|
||||
cancel_program(f"Path does not exist: {file_path.as_posix()}")
|
||||
|
||||
# Collect files to crawl
|
||||
# if dir.
|
||||
if file_path.is_dir():
|
||||
if recursive:
|
||||
blend_files = [
|
||||
f for f in file_path.glob("**/*") if f.is_file() and f.suffix == ".blend"
|
||||
]
|
||||
else:
|
||||
blend_files = [
|
||||
f for f in file_path.iterdir() if f.is_file() and f.suffix == ".blend"
|
||||
]
|
||||
files.extend(blend_files)
|
||||
# If just one file.
|
||||
else:
|
||||
is_filepath_blend(file_path)
|
||||
files.append(file_path)
|
||||
|
||||
# Apply regex.
|
||||
if regex:
|
||||
to_remove: List[Path] = []
|
||||
for p in files:
|
||||
match = re.search(regex, p.as_posix())
|
||||
if not match:
|
||||
to_remove.append(p)
|
||||
Sebastian Parborg
commented
I don't think this program should have any config file at all. Unless the command line tool is very complex (which this one is not), then the user should always have a fresh start each time the command line tool is run. I'll elaborate further in an other comment. I don't think this program should have any config file at all.
Unless the command line tool is very complex (which this one is not), then the user should always have a fresh start each time the command line tool is run.
I'll elaborate further in an other comment.
Nick Alberelli
commented
We handled this together We handled this together https://projects.blender.org/studio/blender-studio-pipeline/commit/9e9c60fda3035acebb0991bad4c24b9643b29b36 issue resolved!
|
||||
|
||||
for p in to_remove:
|
||||
files.remove(p)
|
||||
|
||||
# Can only happen on folder here.
|
||||
if not files:
|
||||
print(" Found no .blend files to crawl")
|
||||
sys.exit(0)
|
||||
|
||||
# Sort.
|
||||
files.sort(key=lambda f: f.name)
|
||||
|
||||
for file in files:
|
||||
print(f"Found: `{file}`")
|
||||
|
||||
if ask_for_confirmation:
|
||||
if not prompt_confirm(len(files)):
|
||||
sys.exit(0)
|
||||
|
||||
if not scripts:
|
||||
cancel_program(
|
||||
"No script files were provided to execute."
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
# crawl each file two times.
|
||||
for blend_file in files:
|
||||
for script in scripts:
|
||||
cmd_list = (
|
||||
blender_exec.as_posix(),
|
||||
blend_file.as_posix(),
|
||||
"-b",
|
||||
"-P",
|
||||
script,
|
||||
"--factory-startup",
|
||||
)
|
||||
process = subprocess.Popen(cmd_list, shell=False)
|
||||
if process.wait() != 0:
|
||||
cancel_program(f"Blender Crashed on file: {blend_file.as_posix()}")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -19,25 +19,19 @@
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
import bpy
|
||||
|
||||
# Setup prefs.
|
||||
bpy.context.preferences.filepaths.save_version = 0
|
||||
bpy.context.preferences.filepaths.save_version = 0 #TODO Figure out why this is here
|
||||
|
||||
# Purge.
|
||||
logger.info("Starting Recursive Purge")
|
||||
print("Starting Recursive Purge")
|
||||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
||||
|
||||
# Save.
|
||||
bpy.ops.wm.save_mainfile()
|
||||
logger.info("Saved file: %s", bpy.data.filepath)
|
||||
print("Saved file: %s", bpy.data.filepath)
|
||||
|
||||
# Quit.
|
||||
logger.info("Closing File")
|
||||
print("Closing File")
|
||||
bpy.ops.wm.quit_blender()
|
33
scripts/blender-crawl/setup.py
Normal file
33
scripts/blender-crawl/setup.py
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python
|
||||
"""The setup script for blender-crawl."""
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
with open("README.md") as readme_file:
|
||||
readme = readme_file.read()
|
||||
|
||||
|
||||
setup(
|
||||
author="Nick Alberelli",
|
||||
author_email="nick@blender.org",
|
||||
python_requires=">=3.5",
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"Natural Language :: English",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
],
|
||||
description="Command line tool to perform recursive crawl blend files from the console",
|
||||
long_description=readme,
|
||||
include_package_data=True,
|
||||
keywords="blender_crawl",
|
||||
name="blender_crawl",
|
||||
packages=["blender_crawl", "blender_crawl.default_scripts",],
|
||||
version="0.1.0",
|
||||
entry_points={"console_scripts": ["blender_crawl = blender_crawl.__main__:main"]},
|
||||
package_data={'blender_crawl.default_scripts': ['*']}, #TODO Verify this is working correctly after install
|
||||
)
|
106
scripts/blender-purge/.gitignore
vendored
106
scripts/blender-purge/.gitignore
vendored
@ -1,106 +0,0 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
.venv*
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# IDE settings
|
||||
.vscode/
|
@ -1,71 +0,0 @@
|
||||
# blender-purge
|
||||
blender-purge is a command line tools to purge orphan data of blend files via the console.
|
||||
|
||||
## Table of Contents
|
||||
- [Prerequisite](#prerequisite)
|
||||
- [Installation](#installation)
|
||||
- [How to get started](#how-to-get-started)
|
||||
- [Development](#development)
|
||||
|
||||
## Prerequisite
|
||||
In order to use this tool you need:
|
||||
- python3
|
||||
- pip
|
||||
- svn
|
||||
|
||||
## Installation
|
||||
Download or clone this repository.
|
||||
This repository is a command line tool that can be installed with the python packaging manager.
|
||||
In the root of this project you can find a `install.sh` script which simplifies this process on linux.
|
||||
|
||||
This script does the following (follow this if you want to do this manually or on another platform):
|
||||
|
||||
1. Install pip
|
||||
2. Open a terminal in the root of the project directory
|
||||
3. Run `python3 setup.py bdist_wheel` which builds a wheel in ./dist
|
||||
4. Run `pip3 install dist/<name_of_wheel> --user`
|
||||
|
||||
Ensure your $PATH variable contains:
|
||||
|
||||
Linux/MacOs:
|
||||
- `$HOME/.local/lib/python3.8/site-packages`
|
||||
- `$HOME/.local/bin`
|
||||
|
||||
Windows:
|
||||
- TODO
|
||||
|
||||
Open a new console and write `bpurge` to verify successful install.
|
||||
|
||||
## How to get started
|
||||
After install you can write `bpurge` in to the console.
|
||||
|
||||
If you use the tool the first time it will ask you to specify a path to a blender executable and a path to the svn project directory, which will be saved in a configuration file:
|
||||
|
||||
Linux/MacOs:
|
||||
- `$home/.config/blender-purge/config.json`
|
||||
|
||||
Windows:
|
||||
- `$home/blender-purge/config.json`
|
||||
|
||||
|
||||
Give `bpurge` a path to a .blend file or a folder as first argument.
|
||||
The detected blend files will be opened in the background, their orphan data will be
|
||||
purged recursively, the file gets saved and closed again. This will happen twice for each .blend file.
|
||||
|
||||
You can modify the tool by providing these command line arguments:
|
||||
|
||||
- first arguments needs to be a path to a .blend file or a folder
|
||||
|
||||
- **-R / --recursive**: If -R is provided in combination with a folder path will perform recursive purge.
|
||||
|
||||
- **-N / --nocommit**: If -N is provided there will be no svn commit prompt with the purged files.
|
||||
|
||||
- **--regex**: Provide any regex pattern that will be performed on each found filepath with re.search().
|
||||
|
||||
- **--yes**: If --yes is provided there will be no confirmation prompt.
|
||||
|
||||
|
||||
## Development
|
||||
In the project root you will find a `pyproject.toml` and `peotry.lock` file.
|
||||
With `poetry` you can easily generate a virtual env for the project which should get you setup quickly.
|
||||
Basic Usage: https://python-poetry.org/docs/basic-usage/
|
@ -1,25 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
"""Top-level package for blender_purge."""
|
||||
|
||||
__author__ = """Paul Golter"""
|
||||
__email__ = "paul@blender.org"
|
||||
__version__ = "0.1.0"
|
@ -1,328 +0,0 @@
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Tuple, List, Dict, Any, Union, Optional
|
||||
|
||||
from blender_purge import vars
|
||||
from blender_purge.svn import SvnRepo
|
||||
from blender_purge.log import LoggerFactory
|
||||
from blender_purge.exception import SomethingWentWrongException, WrongInputException
|
||||
|
||||
logger = LoggerFactory.getLogger()
|
||||
|
||||
|
||||
def exception_handler(func):
|
||||
def func_wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
except WrongInputException as error:
|
||||
logger.info(
|
||||
"# Oops. Seems like you gave some wrong input!"
|
||||
f"\n# Error: {error}"
|
||||
"\n# Program will be cancelled."
|
||||
)
|
||||
cancel_program()
|
||||
|
||||
except SomethingWentWrongException as error:
|
||||
logger.info(
|
||||
"# Oops. Something went wrong during the execution of the Program!"
|
||||
f"\n# Error: {error}"
|
||||
"\n# Program will be cancelled."
|
||||
)
|
||||
cancel_program()
|
||||
|
||||
return func_wrapper
|
||||
|
||||
|
||||
def cancel_program() -> None:
|
||||
logger.info("# Exiting blender-purge")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def get_blender_path() -> Path:
|
||||
config_path = get_config_path()
|
||||
json_obj = load_json(config_path)
|
||||
return Path(json_obj["blender_path"])
|
||||
|
||||
|
||||
def get_project_root_path() -> Path:
|
||||
config_path = get_config_path()
|
||||
json_obj = load_json(config_path)
|
||||
return Path(json_obj["project_root"])
|
||||
|
||||
|
||||
def get_cmd_list(path: Path) -> Tuple[str]:
|
||||
cmd_list: Tuple[str] = (
|
||||
get_blender_path().as_posix(),
|
||||
path.as_posix(),
|
||||
"-b",
|
||||
"-P",
|
||||
f"{vars.PURGE_PATH}",
|
||||
"--factory-startup",
|
||||
)
|
||||
return cmd_list
|
||||
|
||||
|
||||
def validate_user_input(user_input, options):
|
||||
if user_input.lower() in options:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def prompt_confirm(path_list: List[Path]):
|
||||
options = ["yes", "no", "y", "n"]
|
||||
list_str = "\n".join([p.as_posix() for p in path_list])
|
||||
noun = "files" if len(path_list) > 1 else "file"
|
||||
confirm_str = f"# Do you want to purge {len(path_list)} {noun}? ([y]es/[n]o)"
|
||||
input_str = "# Files to purge:" + "\n" + list_str + "\n\n" + confirm_str
|
||||
while True:
|
||||
user_input = input(input_str)
|
||||
if validate_user_input(user_input, options):
|
||||
if user_input in ["no", "n"]:
|
||||
logger.info("\n# Process was canceled.")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
logger.info("\n# Please enter a valid answer!")
|
||||
continue
|
||||
|
||||
|
||||
def run_check():
|
||||
cmd_list: Tuple[str] = (
|
||||
get_blender_path().as_posix(),
|
||||
"-b",
|
||||
"-P",
|
||||
f"{vars.CHECK_PATH}",
|
||||
)
|
||||
p = subprocess.Popen(cmd_list)
|
||||
return p.wait()
|
||||
|
||||
|
||||
def purge_file(path: Path) -> int:
|
||||
# Get cmd list.
|
||||
cmd_list = get_cmd_list(path)
|
||||
p = subprocess.Popen(cmd_list, shell=False)
|
||||
# Stdout, stderr = p.communicate().
|
||||
return p.wait()
|
||||
|
||||
|
||||
def is_filepath_valid(path: Path) -> None:
|
||||
|
||||
# Check if path is file.
|
||||
if not path.is_file():
|
||||
raise WrongInputException(f"Not a file: {path.suffix}")
|
||||
|
||||
# Check if path is blend file.
|
||||
if path.suffix != ".blend":
|
||||
raise WrongInputException(f"Not a blend file: {path.suffix}")
|
||||
|
||||
|
||||
def get_config_path() -> Path:
|
||||
home = Path.home()
|
||||
|
||||
if sys.platform == "win32":
|
||||
return home / "blender-purge/config.json"
|
||||
elif sys.platform == "linux":
|
||||
return home / ".config/blender-purge/config.json"
|
||||
elif sys.platform == "darwin":
|
||||
return home / ".config/blender-purge/config.json"
|
||||
|
||||
|
||||
def create_config_file(config_path: Path) -> None:
|
||||
if config_path.exists():
|
||||
return
|
||||
try:
|
||||
with open(config_path.as_posix(), "w") as file:
|
||||
json.dump({}, file)
|
||||
except:
|
||||
raise SomethingWentWrongException(
|
||||
f"# Something went wrong creating config file at: {config_path.as_posix()}"
|
||||
)
|
||||
|
||||
logger.info(f"# Created config file at: {config_path.as_posix()}")
|
||||
|
||||
|
||||
def load_json(path: Path) -> Any:
|
||||
with open(path.as_posix(), "r") as file:
|
||||
obj = json.load(file)
|
||||
return obj
|
||||
|
||||
|
||||
def save_to_json(obj: Any, path: Path) -> None:
|
||||
with open(path.as_posix(), "w") as file:
|
||||
json.dump(obj, file, indent=4)
|
||||
|
||||
|
||||
def input_path(question: str) -> Path:
|
||||
while True:
|
||||
user_input = input(question)
|
||||
try:
|
||||
path = Path(user_input)
|
||||
except:
|
||||
logger.error("# Invalid input")
|
||||
continue
|
||||
if path.exists():
|
||||
return path.absolute()
|
||||
else:
|
||||
logger.info("# Path does not exist")
|
||||
|
||||
|
||||
def input_filepath(question: str) -> Path:
|
||||
while True:
|
||||
path = input_path(question)
|
||||
if not path.is_file():
|
||||
continue
|
||||
return path
|
||||
|
||||
|
||||
def setup_config() -> None:
|
||||
config_path = get_config_path()
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
blender_path = input_filepath("# Path to Blender binary: ")
|
||||
project_root = input_path("# Path to SVN project root: ")
|
||||
obj = {
|
||||
"blender_path": blender_path.as_posix(),
|
||||
"project_root": project_root.as_posix(),
|
||||
}
|
||||
save_to_json(obj, config_path)
|
||||
logger.info("Updatet config at: %s", config_path.as_posix())
|
||||
|
||||
|
||||
def is_config_valid() -> bool:
|
||||
keys = ["blender_path", "project_root"]
|
||||
config_path = get_config_path()
|
||||
json_obj = load_json(config_path)
|
||||
for key in keys:
|
||||
if key not in json_obj:
|
||||
return False
|
||||
if not json_obj[key]:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@exception_handler
|
||||
def purge(args: argparse.Namespace) -> int:
|
||||
|
||||
# Parse arguments.
|
||||
path = Path(args.path).absolute()
|
||||
recursive = args.recursive
|
||||
config_path = get_config_path()
|
||||
no_commit = args.nocommit
|
||||
regex = args.regex
|
||||
yes = args.yes
|
||||
|
||||
# Check config file.
|
||||
if not config_path.exists():
|
||||
logger.info("# Seems like you are starting blender-purge for the first time!")
|
||||
logger.info("# Some things needs to be configured")
|
||||
setup_config()
|
||||
else:
|
||||
if not is_config_valid():
|
||||
logger.info("# Config file at: %s is not valid", config_path.as_posix())
|
||||
logger.info("# Please set it up again")
|
||||
setup_config()
|
||||
|
||||
# Check user input.
|
||||
if not path:
|
||||
raise WrongInputException("Please provide a path as first argument")
|
||||
|
||||
if not path.exists():
|
||||
raise WrongInputException(f"Path does not exist: {path.as_posix()}")
|
||||
|
||||
# Vars.
|
||||
files = []
|
||||
|
||||
# Collect files to purge
|
||||
# if dir.
|
||||
if path.is_dir():
|
||||
if recursive:
|
||||
blend_files = [
|
||||
f for f in path.glob("**/*") if f.is_file() and f.suffix == ".blend"
|
||||
]
|
||||
else:
|
||||
blend_files = [
|
||||
f for f in path.iterdir() if f.is_file() and f.suffix == ".blend"
|
||||
]
|
||||
files.extend(blend_files)
|
||||
# If just one file.
|
||||
else:
|
||||
is_filepath_valid(path)
|
||||
files.append(path)
|
||||
|
||||
# Apply regex.
|
||||
if regex:
|
||||
to_remove: List[Path] = []
|
||||
for p in files:
|
||||
match = re.search(regex, p.as_posix())
|
||||
if not match:
|
||||
to_remove.append(p)
|
||||
|
||||
for p in to_remove:
|
||||
files.remove(p)
|
||||
|
||||
# Can only happen on folder here.
|
||||
if not files:
|
||||
logger.info("# Found no .blend files to purge")
|
||||
cancel_program()
|
||||
|
||||
# Sort.
|
||||
files.sort(key=lambda f: f.name)
|
||||
|
||||
# Prompt confirm.
|
||||
if not yes:
|
||||
if not prompt_confirm(files):
|
||||
cancel_program()
|
||||
|
||||
"""
|
||||
# Perform check of correct preference settings.
|
||||
return_code = run_check()
|
||||
if return_code == 1:
|
||||
raise SomethingWentWrongException(
|
||||
"Override auto resync is turned off. Turn it on in the preferences and try again."
|
||||
)
|
||||
"""
|
||||
|
||||
# Purge each file two times.
|
||||
for blend_file in files:
|
||||
for i in range(vars.PURGE_AMOUNT):
|
||||
return_code = purge_file(blend_file)
|
||||
if return_code != 0:
|
||||
raise SomethingWentWrongException(
|
||||
f"Blender Crashed on file: {blend_file.as_posix()}",
|
||||
)
|
||||
|
||||
# Commit to svn.
|
||||
if no_commit:
|
||||
return 0
|
||||
|
||||
project_root = get_project_root_path()
|
||||
svn_repo = SvnRepo(project_root)
|
||||
file_rel = [p.relative_to(project_root) for p in files]
|
||||
svn_repo.commit(file_rel)
|
||||
return 0
|
@ -1,32 +0,0 @@
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import sys
|
||||
import bpy
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Check if recursive is on.
|
||||
if not bpy.context.preferences.experimental.override_auto_resync:
|
||||
logger.error("Override auto resync is turned off!")
|
||||
sys.exit(1)
|
@ -1,72 +0,0 @@
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import importlib
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from blender_purge import app
|
||||
from blender_purge.log import LoggerFactory
|
||||
|
||||
importlib.reload(app)
|
||||
logger = LoggerFactory.getLogger()
|
||||
|
||||
# Command line arguments.
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"path", help="Path to a file or folder on which to perform purge", type=str
|
||||
)
|
||||
parser.add_argument(
|
||||
"-R",
|
||||
"--recursive",
|
||||
help="If -R is provided in combination with a folder path will perform recursive purge",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-N",
|
||||
"--nocommit",
|
||||
help="If -N is provided there will be no svn commit prompt with the purged files.",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--regex",
|
||||
help="Provide any regex pattern that will be performed on each found filepath with re.search()",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--yes",
|
||||
help="If --yes is provided there will be no confirmation prompt.",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
app.purge(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,27 +0,0 @@
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
class WrongInputException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class SomethingWentWrongException(Exception):
|
||||
pass
|
@ -1,42 +0,0 @@
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
|
||||
class LoggerFactory:
|
||||
|
||||
"""
|
||||
Utility class to streamline logger creation
|
||||
"""
|
||||
|
||||
formatter = logging.Formatter("%(name)s: %(message)s")
|
||||
consoleHandler = logging.StreamHandler(sys.stdout)
|
||||
level = logging.INFO
|
||||
|
||||
@classmethod
|
||||
def getLogger(cls, name=__name__):
|
||||
logger = logging.getLogger(name)
|
||||
logger.addHandler(cls.consoleHandler)
|
||||
logger.setLevel(cls.level)
|
||||
|
||||
return logger
|
@ -1,118 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
from typing import List, Union, Tuple, Any, Dict, Optional
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class SvnRepo:
|
||||
def __init__(self, path: Path) -> None:
|
||||
self._orig_pwd = Path(os.path.abspath(os.getcwd()))
|
||||
self._path = path.absolute()
|
||||
|
||||
@property
|
||||
def path(self) -> Path:
|
||||
return self._path
|
||||
|
||||
def status(self) -> List[str]:
|
||||
output = str(
|
||||
subprocess.check_output(
|
||||
["svn status"], shell=True, cwd=self._path.as_posix()
|
||||
),
|
||||
"utf-8",
|
||||
)
|
||||
# Split output in string lines.
|
||||
split = output.split("\n")
|
||||
|
||||
# Remove empty lines.
|
||||
while True:
|
||||
try:
|
||||
split.remove("")
|
||||
except ValueError:
|
||||
break
|
||||
return split
|
||||
|
||||
def get_modified(self, suffix: str = ".*") -> List[Path]:
|
||||
output = self.status()
|
||||
if not output:
|
||||
return []
|
||||
|
||||
path_list: List[Path] = []
|
||||
|
||||
# Assemble path list.
|
||||
for idx, line in enumerate(output):
|
||||
if not line.startswith("M"):
|
||||
continue
|
||||
path = Path(line[5:].strip())
|
||||
|
||||
# If no suffix supplied append all files.
|
||||
if suffix == ".*":
|
||||
path_list.append(path)
|
||||
# If suffix supplied only collect files that match.
|
||||
else:
|
||||
if path.suffix == suffix:
|
||||
path_list.append(path)
|
||||
|
||||
return path_list
|
||||
|
||||
def revert(self, relpath_list: List[Path]) -> subprocess.Popen:
|
||||
arg_list = " ".join([p.as_posix() for p in relpath_list])
|
||||
process = subprocess.call(
|
||||
(f"svn revert {arg_list}"), shell=True, cwd=self._path.as_posix()
|
||||
)
|
||||
return process
|
||||
|
||||
def revert_all(self) -> None:
|
||||
modified = self.get_modified()
|
||||
self.revert(modified)
|
||||
|
||||
def commit(self, relpath_list: List[Path]) -> Optional[subprocess.Popen]:
|
||||
if not relpath_list:
|
||||
return None
|
||||
|
||||
cmd_list = f'svn commit {" ".join([p.as_posix() for p in relpath_list])}'
|
||||
process = subprocess.call(cmd_list, shell=True, cwd=self._path.as_posix())
|
||||
return process
|
||||
|
||||
def get_untracked(self) -> List[Path]:
|
||||
output = self.status()
|
||||
if not output:
|
||||
return []
|
||||
|
||||
path_list: List[Path] = []
|
||||
|
||||
# Assemble path list.
|
||||
for idx, line in enumerate(output):
|
||||
if not line.startswith("?"):
|
||||
continue
|
||||
path = Path(line[5:].strip())
|
||||
path_list.append(path)
|
||||
|
||||
return path_list
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test status.
|
||||
repo = SvnRepo(Path("/media/data/sprites"))
|
||||
modified = repo.get_modified()
|
||||
print(modified)
|
||||
repo.commit(modified[:2])
|
@ -1,29 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
#
|
||||
# (c) 2021, Blender Foundation
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
PURGE_PATH = Path(os.path.abspath(__file__)).parent.joinpath("purge.py")
|
||||
CHECK_PATH = Path(os.path.abspath(__file__)).parent.joinpath("check.py")
|
||||
|
||||
BLENDER_PATH = "/media/data/blender_guest/cmake_release/bin/blender"
|
||||
PROJECT_PATH = "/media/data/sprites"
|
||||
PURGE_AMOUNT = 2
|
@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color.
|
||||
|
||||
# Check if pip3 is installed.
|
||||
if ! command -v pip3 &> /dev/null
|
||||
then
|
||||
echo "Pip3 is not installed"
|
||||
|
||||
# Ask user to install pip.
|
||||
while true; do
|
||||
read -p "Do you wish to install this program? (Yy/Nn)" yn
|
||||
case $yn in
|
||||
[Yy]* ) sudo apt install python3-pip; break;;
|
||||
[Nn]* ) exit;;
|
||||
* ) echo "Please answer yes or no.";;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Cd into directory of install.sh script.
|
||||
dirpath=`dirname "$0"`
|
||||
cd $dirpath
|
||||
|
||||
# Build wheel.
|
||||
python3 setup.py bdist_wheel
|
||||
|
||||
# Install wheel with pip.
|
||||
pip3 install dist/blender_purge-0.1.0-py2.py3-none-any.whl --user --force-reinstall
|
||||
|
||||
# Check if PATH variable is correct.
|
||||
if ! [[ ":$PATH:" == *":$HOME/.local/lib/python3.8/site-packages:"* ]]; then
|
||||
printf "\n${RED}\$HOME/.local/lib/python3.8/site-packages is missing in PATH variable\n"
|
||||
printf "Please add 'export PATH=\"\$PATH:$HOME/.local/lib/python3.8/site-packages\"' to the file: \$HOME/.profile${NC}\n"
|
||||
fi
|
||||
|
||||
if ! [[ ":$PATH:" == *":$HOME/.local/bin:"* ]]; then
|
||||
printf "\n${RED}\$HOME/.local/bin is missing in PATH variable\n"
|
||||
printf "Please add 'export PATH=\"\$PATH:$HOME/.local/bin\"' to the file: \$HOME/.profile${NC}\n"
|
||||
fi
|
||||
|
||||
# Log end.
|
||||
printf "\n${GREEN}Installed blender-purge. Type 'bpurge' in console to start program!\n"
|
||||
printf "To uninstall type 'pip3 uninstall blender-purge'${NC}\n"
|
@ -1,16 +0,0 @@
|
||||
[bumpversion]
|
||||
current_version = 0.1.0
|
||||
commit = True
|
||||
tag = True
|
||||
|
||||
[bumpversion:file:setup.py]
|
||||
search = version='{current_version}'
|
||||
replace = version='{new_version}'
|
||||
|
||||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
[flake8]
|
||||
exclude = docs
|
||||
|
||||
[aliases]
|
@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""The setup script."""
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("README.md") as readme_file:
|
||||
readme = readme_file.read()
|
||||
|
||||
with open("HISTORY.md") as history_file:
|
||||
history = history_file.read()
|
||||
|
||||
requirements = []
|
||||
|
||||
setup_requirements = []
|
||||
|
||||
test_requirements = []
|
||||
|
||||
setup(
|
||||
author="Paul Golter",
|
||||
author_email="paul@blender.org",
|
||||
python_requires=">=3.5",
|
||||
classifiers=[
|
||||
"Development Status :: 2 - Pre-Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Natural Language :: English",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
],
|
||||
description="Command line tool to perform recursive purge of blend files in the console",
|
||||
install_requires=requirements,
|
||||
long_description=readme + "\n\n" + history,
|
||||
include_package_data=True,
|
||||
keywords="blender_purge",
|
||||
name="blender_purge",
|
||||
packages=find_packages(include=["blender_purge", "blender_purge.*"]),
|
||||
setup_requires=setup_requirements,
|
||||
test_suite="tests",
|
||||
tests_require=test_requirements,
|
||||
version="0.1.0",
|
||||
zip_safe=False,
|
||||
entry_points={"console_scripts": ["bpurge=blender_purge.cli:main"]},
|
||||
)
|
Loading…
Reference in New Issue
Block a user
I don't think there is much of a reason to have this function?
When I look at the code, it seems like all calls to this could be replaced with
sys.exit(0)
without any loss.We handled this together on the phone! Issue has been resolved.
81083cdb01