def uninstall(plugin): """Uninstall a plugin""" profile = config.plugins.profile dest_dir = profile.pluginsdir def plugin_location(plugin): return os.path.join(dest_dir, "{}.py".format(plugin_file_name(plugin))) for _plugin in plugin: plugin_name = _plugin.replace('/', '_') from click_project.plugins import plugins plugin_mod = plugins.load_plugin(plugin_name) if hasattr(plugin_mod, "before_uninstall"): plugin_mod.before_uninstall() if not os.path.exists(plugin_location(_plugin)): LOGGER.warning("Plugin {} does not exist in profile {}.".format( _plugin, profile.name, )) continue LOGGER.status("Uninstalling plugin {} from profile {}".format( _plugin, profile.name)) pl = plugin_location(_plugin) rm(pl) if os.path.exists(pl + 'c'): rm(pl + 'c')
def tesseract(input, language, remove_after): """Extract the text from a pdf and create a searchable pdf""" ocr_base = os.path.splitext(input)[0] + "_ocr" with temporary_file(suffix=".tiff") as tiff: call(split(f"convert -density 300 '{input}' -depth 8 '{tiff.name}'")) call(split(f"tesseract '{tiff.name}' '{ocr_base}' -l '{language}' pdf")) if remove_after: rm(input)
def recipes_instead_of_settings_level(self): if self.isrecipe: return True recipes_dir = self.location + "/recipes/" def migrate_settings_to_recipe(settings_level_file, name): if open(settings_level_file, "rb").read().decode("utf-8").strip() == "{}": return False makedirs(recipes_dir + "/" + name) enabled = not json.load(open(settings_level_file)).get( "_self", {}).get("disabled", False) order = json.load(open(settings_level_file)).get("_self", {}).get( "order", 100) move(settings_level_file, recipes_dir + "/" + name + "/{}.json".format(self.app_name)) createfile(recipes_dir + "/" + name + "/version.txt", str(self.version + 1)) createfile(recipes_dir + "/" + name + ".json", json.dumps({ "enabled": enabled, "order": order, })) return True migrate_something = False for settings_level_file in glob(self.location + "/{}-*.json".format(self.app_name)): name = re.sub(".+{}-([a-zA-Z-]+).json$".format(self.app_name), r"\1", settings_level_file) name = name.replace("-", "_") if name == "private": continue migrate_something |= migrate_settings_to_recipe( settings_level_file, name + "_from_settings") private = self.location + "/{}-private.json".format(self.app_name) local = self.location + "/{}.json".format(self.app_name) if os.path.exists(private): if open(private, "rb").read().decode("utf-8").strip() != "{}": migrate_something = True else: rm(private) if migrate_something is True: name = "migrated_local" if os.path.exists(local) and not open( local, "rb").read().decode("utf-8").strip() == "{}": migrate_settings_to_recipe(local, name) if os.path.exists(private): move(private, local) with json_file(local) as values: recipes = values.get("recipe", {}) local_order = recipes.get(name, {}) local_order["order"] = 0 recipes[name] = local_order values["recipe"] = recipes self.computed_location = None self.compute_settings() return True
def clean(): """Remove the files/directories known by git from your file system It makes the file system bare naked, like before the first restore call. """ for rel in config.git_record.readonly.keys(): full = os.path.join(config.project, rel) if os.path.exists(full): LOGGER.status("Removing {}".format(rel)) rm(full)
def migrate(self, persist=True): LOGGER.action("migrate profile in {}".format(self.location)) if self.dry_run: return False if os.path.exists(self.backup_location): LOGGER.error( "{} already exists. Cannot migrate.".format(self.backup_location) ) return False makedirs(self.backup_location) for name in self.migration_impact: if os.path.exists(os.path.join(self.location, name)): copy( os.path.join(self.location, name), os.path.join(self.backup_location, name), ) try: res = self._migrate(persist) except Exception as e: import traceback LOGGER.error(e) LOGGER.develop(traceback.format_exc()) res = False if res: rm(self.backup_location) else: if persist: LOGGER.warning( "The migration of {} did not go well," " Restoring backup from {}".format( self.location, self.backup_location ) ) for name in self.migration_impact: if os.path.exists(os.path.join(self.backup_location, name)): if os.path.exists(os.path.join(self.location, name)): rm( os.path.join(self.location, name) ) copy( os.path.join(self.backup_location, name), os.path.join(self.location, name), ) rm(self.backup_location) return res
def install_plugin(profile, force, plugin, login, password, develop, no_deps): """Install a plugin""" dest_dir = profile.pluginsdir def plugin_location(plugin): return os.path.join(dest_dir, "{}.py".format(plugin_file_name(plugin))) for _plugin in plugin: if not force and os.path.exists(plugin_location(_plugin)): raise click.UsageError( "{} already installed in profile {}." " If you really want to install it, use --force or" " run plugin uninstall --{} {}".format(_plugin, profile.name, profile.name, _plugin)) for _plugin in plugin: if is_local_plugin(_plugin): if _plugin.startswith("file://"): content = open(_plugin[len("file://"):], "rb").read().decode("utf-8") plugin_file = os.path.abspath(_plugin[len("file://"):]) else: content = open(_plugin, "rb").read().decode("utf-8") plugin_file = os.path.abspath(_plugin) plugin_name = os.path.basename(plugin_file)[:-3] plugin_dir = os.path.dirname(plugin_file) if os.path.basename(plugin_dir) != "{}_plugins".format( config.app_name): raise click.UsageError( "{} does not look like a plugin directory".format( plugin_dir)) user_name = os.path.basename(os.path.dirname(plugin_dir)) plugin_name = "{}/{}".format(user_name, plugin_name) else: content = get_plugin_from_remote(_plugin) plugin_name = _plugin def install_requirements(): require_prefix = "# require: " requires = [ line[len(require_prefix):] for line in content.splitlines() if line.startswith(require_prefix) ] for require in requires: LOGGER.status("Installing requirement {}".format(require)) args = ['--upgrade', require] if force: args.append("--force-reinstall") pip("install", args) plugin_require_prefix = "# plugin_require: " plugin_requires = [ line[len(plugin_require_prefix):] for line in content.splitlines() if line.startswith(plugin_require_prefix) ] for plugin_require in plugin_requires: LOGGER.status( "Installing plugin requirements {}".format(plugin_require)) install_plugin( profile=profile, force=force, login=login, password=password, plugin=[plugin_require], develop=False, no_deps=no_deps, ) if not no_deps: install_requirements() LOGGER.status("Installing plugin {} in profile {}".format( plugin_name, profile.name)) location = plugin_location(plugin_name) makedirs(os.path.dirname(location)) if is_local_plugin(_plugin) and develop: LOGGER.debug("Installing {} in develop mode".format(plugin_name)) if force and os.path.exists(location): rm(location) ln(plugin_file, location) else: createfile(location, content)
def remove_recipe(self, name): r = self.get_recipe(name) rm(r.location)
def _unset(recipes): """Remove the the link file""" for recipe in recipes: rm(config.recipe.profile.link_location(recipe)) LOGGER.status("Removing the link file of {} ({})".format( recipe, config.recipe.writeprofile))
def remove(force, customcommand): """Remove the given custom command""" path = Path(customcommand.customcommand_path) if force or click.confirm(f"This will remove {path}, are you sureĀ ?"): rm(path)
def fork(force, name): """Create a brand new project, based on clk that can be used by itself.""" output = Path(name) if output.exists(): if force: rm(output) else: raise click.UsageError(f"{output} already exist") makedirs(output) createfile( output / "setup.py", f"""#!/usr/bin/env python3 # -*- coding:utf-8 -*- from setuptools import setup, find_packages setup( name='{name}', version="0.0.0", packages=find_packages(), zip_safe=False, install_requires=[ "click-project", ], entry_points={{ 'console_scripts': [ '{name}={name}.main:main', ] }}, ) """) package = (output / name) makedirs(package) createfile( package / "main.py", f"""#!/usr/bin/env python3 # -*- coding:utf-8 -*- from click_project.setup import basic_entry_point, main from click_project.decorators import command, argument, flag, option @basic_entry_point( __name__, extra_command_packages=["{name}.commands"], exclude_core_commands=["git-sync"], ) def {name}(**kwargs): pass if __name__ == "__main__": main() """) createfile(package / "__init__.py", f"""#!/usr/bin/env python3""") commands = (package / "commands") makedirs(commands) (commands / "somecommand.py", """#!/usr/bin/env python3 # -*- coding:utf-8 -*- import click from click_project.decorators import command, argument, flag, option from click_project.log import get_logger LOGGER = get_logger(__name__) @command() @argument("some-argument", help="some argument") @flag("--some-flag/--no-some-flag", help="some flag") @option("--some-option", help="some option") def somecommand(some_argument, some_flag, some_option): "Some command" LOGGER.info(some_argument) LOGGER.info(some_flag) LOGGER.info(some_option) """) print(f"Now, install {name} with `python3 -m pip install {name}`," f" enable its completion with `{name} completion install`" f" and don't forget to have fun")
def remove(force, profile_source, plugin): """Remove the given custom command""" path = Path(profile_source.location) / "plugins" / (plugin + ".py") if force or click.confirm(f"This will remove {path}, are you sureĀ ?"): rm(path)