def main(): """ Main method """ sys.argv[0] = "c3pm" if len(sys.argv) < 2: CLIMessage.error_message( "At least one CLI argument expected") # TODO show usage sys.exit() if sys.argv[1] == "init" and len(sys.argv) == 2: CLIMain.__init_project() return if sys.argv[1] == "add": if sys.argv[2] == "git-c3pm": if sys.argv[5] == "master" and len(sys.argv) == 6: CLIMain.__add_git_c3pm_dependency(sys.argv[3], sys.argv[4]) return if sys.argv[1] == "remove" and len(sys.argv) == 4: CLIMain.__remove_dependency(sys.argv[2], sys.argv[3]) return if sys.argv[1] == "update" and len(sys.argv) == 2: CLIMain.__update_dependencies() return if sys.argv[1] == "list" and len(sys.argv) == 2: CLIMain.__list_dependencies() return CLIMessage.error_message("bad CLI usage")
def __list_dependencies(): """ Lists all dependencies to CLI """ try: c3pm_project = C3PMProject(is_object=True) project_dependencies_dict = c3pm_project.list_all_dependencies() if project_dependencies_dict: ColorP.print("Dependencies for " + c3pm_project.name + ":", ColorP.BOLD_CYAN) for dependency_name in project_dependencies_dict: if project_dependencies_dict[dependency_name][ "type"] == "git-c3pm": ColorP.print("├─── ", ColorP.BOLD_CYAN, line_end="") print( C3PMProject.dependency_str_representation( dependency_name, project_dependencies_dict[dependency_name], colored=True)) else: ColorP.print( "Project " + c3pm_project.name + " doesn't have any dependencies", ColorP.BOLD_CYAN) except C3PMProject.BadC3PMProject as err: CLIMessage.error_message("bad project: " + err.problem) sys.exit() except Exception: CLIMessage.error_message( "unknown error happen, please, report the following on " + CLIMain.ISSUES_LINK) raise
def __add_git_c3pm_dependency(name: str, git_url: str, version: str = "master"): """ Add dependency of type c3pm_dependency :param name: name for new dependency :param git_url: url of .git repository :param version: have to "master" at this moment """ try: c3pm_project = C3PMProject(is_object=True) c3pm_project.add_c3pm_dependency(name, git_url, version) c3pm_project.write() except C3PMProject.BadC3PMProject as err: CLIMessage.error_message("bad project: " + err.problem) sys.exit() except C3PMProject.BadValue as err: CLIMessage.error_message("bad argument: " + str(err)) sys.exit() except Exception: CLIMessage.error_message( "unknown error happen, please, report the following on " + CLIMain.ISSUES_LINK) raise else: CLIMessage.success_message( "dependency " + C3PMProject.dependency_str_representation( name, c3pm_project.dependency_data(name)) + " successfully added to project")
def clone_git_repository(name: str, url: str, target_directory_name: str): """ Clones git repository by url and checks is it cloned correct :param name: name of project which will be cloned :param url: url of .git repository :param target_directory_name: a directory name for cloning :raises C3PMProject.BadValue: if cloning failed """ CLIMessage.info_message("cloning " + name + " (" + url + ") to " + target_directory_name) os.system("git clone " + url + " " + target_directory_name) clone_dir_ls = subprocess.check_output(["ls"]).split() if len(clone_dir_ls) == 0: raise C3PMProject.BadValue( "url", "cloning " + name + " (" + url + ") to " + target_directory_name + " failed: nothing cloned.") if len(clone_dir_ls) != 1: raise C3PMProject.BadValue( "url", "cloning " + name + " (" + url + ") to " + target_directory_name + " failed: to many directories in " "clone directory.") CLIMessage.success_message(name + " cloned")
def __init_project(): """ Initialize a new c3pm project by creating c3pm.json by users data via CLI, (if not exist) "src" and "src/exports". Adds IMPORT_DIR and CLONE_DIR to .gitignore """ try: c3pm_project = C3PMProject(is_object=True, init_new_project=True) c3pm_project.write() except C3PMProject.BadC3PMProject as err: CLIMessage.error_message("bad project directory: " + err.problem) sys.exit() except Exception: CLIMessage.error_message( "unknown error happen, please, report the following on " + CLIMain.ISSUES_LINK) raise else: CLIMessage.success_message(C3PMProject.C3PM_JSON_FILENAME + " successfully written") CLIMessage.success_message("project " + c3pm_project.name + " successfully initialized")
def __update_dependencies(): """ Updates all dependencies in project """ try: c3pm_project = C3PMProject(is_object=True) c3pm_project.update_dependencies() except C3PMProject.BadC3PMProject as err: CLIMessage.error_message("bad project: " + err.problem) sys.exit() except Exception: CLIMessage.error_message( "unknown error happen, please, report the following on " + CLIMain.ISSUES_LINK) raise else: CLIMessage.success_message("project successfully updated")
def __remove_dependency(name: str, version: str = "master"): """ Removes dependencies from project :param name: name of dependency to be removed :param version: version of dependency to be removed, have to be "master" at this moment """ try: c3pm_project = C3PMProject(is_object=True) c3pm_project.remove_dependency(name, version) c3pm_project.write() except C3PMProject.BadC3PMProject as err: CLIMessage.error_message("bad project: " + err.problem) sys.exit() except C3PMProject.BadValue as err: CLIMessage.error_message("bad argument: " + str(err)) sys.exit() except Exception: CLIMessage.error_message( "unknown error happen, please, report the following on " + CLIMain.ISSUES_LINK) raise else: CLIMessage.success_message("dependency " + name + "(version " + version + " successfully removed")
def __init__(self, is_object: bool = False, init_new_project: bool = False): """ If init_new_project is True, directory is checked and if all ok, new c3pm project is being initiated by creating new c3pm.json, creating directories "src" and "src/exports" ( if they do not exist, with file "readme.txt" inside of "src/exports") and making changed to ".gitignore" if this file exist. If init_new_project is False, project is checked and c3pm.json is being read. :param is_object: False by default. If True, checks can c3pm commands be applied to this project, otherwise - is project a valid c3pm project to be cloned. :param init_new_project: if True, new project is being initialized, otherwise project is being loaded :raises C3PMProject.BadC3PMProject if project directory check failed :raises json.decoder.JSONDecodeError: if json_str is not a valid json :raises FileNotFoundError: if self.C3PM_JSON_FILENAME cannot be opened :raises AssertionError: if call parameters are forbidden TODO rewrite constructor removing exceptions except BadC3PMProject and AssetionError """ assert type(is_object) == bool, "argument is_object have to bool" assert type(init_new_project ) == bool, "argument init_new_project have to be bool" if init_new_project: # Checking project directory before starting dialog with user if os.path.isdir(self.C3PM_JSON_FILENAME): raise self.BadC3PMProject(self.C3PM_JSON_FILENAME + " is a directory") if os.path.isfile(self.C3PM_JSON_FILENAME): raise self.BadC3PMProject(self.C3PM_JSON_FILENAME + " already exist") if os.path.isfile(self.SRC_DIR): raise self.BadC3PMProject(self.SRC_DIR + " is a file") if os.path.isfile(self.SRC_DIR + "/" + self.EXPORT_DIR): raise self.BadC3PMProject(self.SRC_DIR + "/" + self.EXPORT_DIR + " is a file") self.__c3pm_dict = OrderedDict() self.init_new_json() try: if not os.path.isdir(self.SRC_DIR): os.mkdir(self.SRC_DIR) CLIMessage.success_message(self.SRC_DIR + " directory created") except: raise self.BadC3PMProject("unable to create directory " + self.SRC_DIR) try: if not os.path.isdir(self.SRC_DIR + "/" + self.EXPORT_DIR): os.mkdir(self.SRC_DIR + "/" + self.EXPORT_DIR) CLIMessage.success_message(self.SRC_DIR + "/" + self.EXPORT_DIR + " directory created") with open(self.SRC_DIR + "/" + self.EXPORT_DIR + "/readme.txt", "w+") as \ readme_file: readme_file.write( "place your files which have to be taken by a dependent " "project") CLIMessage.success_message(self.SRC_DIR + "/" + self.EXPORT_DIR + "/readme.txt written") except: raise self.BadC3PMProject("unable to create directory " + self.SRC_DIR + "/" + self.EXPORT_DIR) if os.path.isdir(".git"): if os.path.isdir(".gitignore"): CLIMessage.error_message(".gitignore is directory!!!") else: gitignore_content = "" if os.path.isfile(".gitignore"): with open(".gitignore", "r") as gitignore_file: gitignore_content = gitignore_file.read() if gitignore_content and gitignore_content[ len(gitignore_content) - 1] != '\n': gitignore_content += "\n" if self.IMPORT_DIR + "/**" not in gitignore_content.split( ): gitignore_content += self.IMPORT_DIR + "/**" + "\n" if self.CLONE_DIR + "/**" not in gitignore_content.split(): gitignore_content += self.CLONE_DIR + "/**" + "\n" with open(".gitignore", "w+") as gitignore_file: gitignore_file.write(gitignore_content) CLIMessage.success_message(".gitinore written") else: problem_with_project = C3PMProject.ProjectChecker.problem_with_project( ) if problem_with_project: raise self.BadC3PMProject(problem_with_project) with open(self.C3PM_JSON_FILENAME, "r") as c3pm_json_file: self.__c3pm_dict = json.loads(c3pm_json_file.read(), object_pairs_hook=OrderedDict) problem_with_c3pm_json = \ C3PMProject.C3PMJSONChecker.problem_with_c3pm_json(self.__c3pm_dict) if problem_with_c3pm_json: raise self.BadC3PMProject("bad " + self.C3PM_JSON_FILENAME + ": " + problem_with_c3pm_json)
def list_all_dependencies(self) -> OrderedDict: """ Loads all project's dependencies recursively to list all their own dependencies. In the result, a list of all projects which have to be loaded is listed. :raises C3PMProject.BadC3PMProject: :return: list of all dependencies """ # TODO clean clone dir def full_dependency_branch(dependency_name: str) -> str: """ Returns one of branches to dependency :param dependency_name: :return: full branch-path to dependency """ result = dependency_name next_dependency_name = dependency_name while next_dependency_name != C3PMProject.ROOT_NAME_FOR_DEPENDENCIES_LIST: next_dependency_name = dependency_parent_list[ next_dependency_name] result = next_dependency_name + "->" + result return result CLIMessage.info_message("Listing all dependencies for project " + self.name) # OrderedDict of all dependencies, will be returned all_dependencies = OrderedDict(self.__c3pm_dict["dependencies"]) # OrderedDict of dependencies, which are not yet checked unchecked_dependencies = OrderedDict(self.__c3pm_dict["dependencies"]) # dict of dependencies parent name (dependency_name: str -> parent_dependency_name: str) dependency_parent_list = dict() os.mkdir(C3PMProject.CLONE_DIR) os.chdir(C3PMProject.CLONE_DIR) for cloned_project_dependency_name in all_dependencies: dependency_parent_list[cloned_project_dependency_name] = \ C3PMProject.ROOT_NAME_FOR_DEPENDENCIES_LIST while len(unchecked_dependencies): unchecked_dependency = unchecked_dependencies.popitem(last=False) unchecked_dependency_name = unchecked_dependency[0] try: C3PMProject.clone_git_repository( full_dependency_branch(unchecked_dependency_name), unchecked_dependency[1]["url"], unchecked_dependency_name) except C3PMProject.BadValue as err: raise C3PMProject.BadC3PMProject(str(err)) else: os.chdir(unchecked_dependency_name) try: c3pm_cloned_project = C3PMProject() cloned_project_dependencies_dict = \ c3pm_cloned_project.__c3pm_dict["dependencies"] for cloned_project_dependency_name in cloned_project_dependencies_dict: if cloned_project_dependency_name in all_dependencies: if cloned_project_dependencies_dict[cloned_project_dependency_name] != \ all_dependencies[cloned_project_dependency_name]: raise C3PMProject.BadC3PMProject( "duplicated dependencies names:\n" # dependency 1 name = + full_dependency_branch( cloned_project_dependency_name) + ":\n" # dependency 1 info = + json.dumps(all_dependencies[ cloned_project_dependency_name], indent=4) + "\n" # dependency 2 name = + full_dependency_branch( c3pm_cloned_project.name) + "->" + cloned_project_dependency_name # dependency 2 info = + cloned_project_dependencies_dict[ cloned_project_dependency_name]) else: all_dependencies[ cloned_project_dependency_name] = OrderedDict( cloned_project_dependencies_dict[ cloned_project_dependency_name]) unchecked_dependencies[ cloned_project_dependency_name] = OrderedDict( cloned_project_dependencies_dict[ cloned_project_dependency_name]) dependency_parent_list[cloned_project_dependency_name] = \ c3pm_cloned_project.name except C3PMProject.BadC3PMProject as err: raise C3PMProject.BadC3PMProject( "in cloned project " + full_dependency_branch(unchecked_dependency_name) + ":bad project directory: " + err.problem) except Exception: raise C3PMProject.BadC3PMProject( "in cloned project " + full_dependency_branch(unchecked_dependency_name) + ":unknown error happen, please report that") os.chdir("..") shutil.rmtree(unchecked_dependency_name) os.chdir("..") shutil.rmtree(C3PMProject.CLONE_DIR) return all_dependencies