From 0b48ba22ea5e5bc8e1e0167ea753e7c63f893c14 Mon Sep 17 00:00:00 2001 From: Pedro Henriques Date: Mon, 23 Jan 2017 16:48:18 +0000 Subject: [PATCH] v1.3.0 -> added more flexibility and customization to the keyword mechanic + changed the content of the php project files + added cpp file content + upgraded the HELP action to be more informative. --- README.md | 26 ++++++--- classes/Application.py | 118 ++++++++++++++++++++++++++++++++++------- classes/CLI.py | 7 ++- classes/__init__.py | 2 +- data/file.json | 34 ++++++++++-- data/help.json | 10 +++- data/keywords.json | 4 +- data/project.json | 16 +++--- main.py | 2 +- 9 files changed, 174 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index abdde5d..edf833c 100644 --- a/README.md +++ b/README.md @@ -63,22 +63,36 @@ In this example, if the program is told to create a new python project (exact sy **Special Keywords:** -The content of files, defined in the JSON files, can have special keywords that will be replaced by dynamic or static data. -All keywords are in the format `|!keyword!|`. The supported keywords are: +The content of files, created by both the file and the project actions, can have special keywords that will be replaced by dynamic or static data. + +All keywords are in the format `|!keyword{multiplier}[case]!|`. +- `keyword`: One of the supported keywords. See below for a list of global keywords, as well as, how to add your own. +- `multiplier` (Optional): An integer (whole number) indicating how many times that keyword replacement should be inserted. +- `case` (Optional): A tag indicating a specific case status for the keyword replacement. The supported tags are: + - `uc`: insert the keyword replacement in UPPERCASE. + - `lc`: insert the keyword replacement in lowercase. + - `t`: insert the keyword replacement Capitalized. + +The **global keywords** are: Keyword | Replace Value | Supported Actions --- | --- | --- copyright | copyright text
see below for details on how to customize the text | project
file project_name | the new project's name | project
file (1) +file_name | the new file's name | project
file +file_type | the new file's type | project
file project_type | the new project's type | project no_www_domain | the new project's name, striped of any starting "www." | project -file_name | the new file's name | file -file_type | the new file's type | file (1) When creating a new file, the code will search the file's path for the first directory with a `.git` folder inside it. That directory will be treated as the file's project_name. -All static keywords and their replacement strings are defined in the `keywords.json` file. -Any keywords added to this file will become usable in file's content. +Adding **custom keywords**: + +All custom keywords and their replacement strings are defined in the `keywords.json` file. +Any keywords added to this file will become usable in all the actions. + +It is valid to use other keywords in the replacement string. + This is also where the copyright text is defined and can be customized. NOTE: the code expects the keyword to have a string as a value in `keywords.json` and will replace it with an empty string if that is not the case. diff --git a/classes/Application.py b/classes/Application.py index 5445038..1adc93e 100644 --- a/classes/Application.py +++ b/classes/Application.py @@ -1,6 +1,6 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Python Project Manager v1.2.1 # +# Python Project Manager v1.3.0 # # # # Copyright 2016, PedroHenriques # # http://www.pedrojhenriques.com # @@ -198,6 +198,21 @@ def executeHelp(self) : help_string += "\n\t- " + key else: # a topic was provided + # split the topic into its parts + topic_parts = topic.split(":") + + # check if a sub topic was provided + sub_topic = True + if (len(topic_parts) == 1) : + # it wasn't + sub_topic = False + + # ask for the base information about this topic + topic += ":base" + + # update the topic parts + topic_parts = topic.split(":") + # get the information relevant for the desired topic if (not self.updateJsonData(topic)) : # the file_type isn't defined, so bail out @@ -213,12 +228,53 @@ def executeHelp(self) : # store the help string help_string = self.json_data + # if a subtopic was provided, add the extra information + if (sub_topic) : + if (topic_parts[1] == "type") : + # get the relevant JSON file's content + sub_topic_json_data = self.parseJSON(self.json_path + topic_parts[0] + ".json") + + # check if the topic is "project" + if (topic_parts[0] == "project") : + # it is, so only loop through the 1st tier of the JSON file + # loop through the JSON's content + for key in sub_topic_json_data : + help_string += "\n\t- " + key + else : + # it isn't, so loop through all the tiers of the JSON file + # loop through the JSON's content + for key in sub_topic_json_data : + help_string += "\n\t- " + self.buildTypesString(key, sub_topic_json_data[key]) + # print the help text print(help_string) # at this point everything went OK return(True) + # builds and returns a string with all the type supported by the various actions + # NOTE: called recursively + def buildTypesString(self, parent_str, data) : + res = "" + + # loop through the data + for key in data : + # check if key's value is a string + if (isinstance(data[key], str)) : + # it is, so this is an end tier which is to be ignored + continue + + # this isn't an end tier + # update the type string with this tier's sub-tiers + res += self.buildTypesString(parent_str + ":" + key, data[key]) + " " + + # check if this tier had any valid sub-tiers + if (len(res) == 0) : + # it didn't, so the type is the tier itself + res = parent_str + + return(res.strip()) + # searches the selected JSON file for the needed information # the changes will be made to self.json_data # return True if successful or False otherwise @@ -283,16 +339,20 @@ def createStructure(self, structure, path) : # build the dictionary with replacement keywords replacements = self.keywords.copy() + # determine this file's extension + aux_pos = key.rfind(".") + if (aux_pos == -1) : + file_extension = "" + else : + file_extension = key[aux_pos + 1:] + + # add this file's name and type to the replacements + replacements["file_name"] = key[:aux_pos] + replacements["file_type"] = file_extension + # check if this file requires the copyright text to be inserted if ("|!copyright!|" in file_content) : # it does - # determine this file's extension - aux_pos = key.rfind(".") - if (aux_pos == -1) : - file_extension = "" - else : - file_extension = key[aux_pos + 1:] - # add the copyright replacement information replacements["copyright"] = self.buildCopyrightString(file_extension) @@ -371,35 +431,53 @@ def deleteDir(self, path) : # NOTE: any keywords found in string not present in replacements will be replaced by an empty string def replaceKeyWords(self, replacements, string) : # the pattern to identify the placeholders - re_pattern = "\|!([^{!]+)\{?(\d+)*\}?!\|" + re_pattern = "\|!([^{!\[\]]+)(\{\d+\})?(\[[^{!\[\]]+\])?!\|" + + # the map between case tag in the regex and the String class function to use + str_func = {"lc" : "lower", "uc" : "upper", "t" : "title"} # loop while there are keywords in the string re_matches = re.search(re_pattern, string) while (re_matches != None) : # grab the re_matches groups - match_groups = re_matches.groups() + match_groups = re_matches.groups("") + match_count = len(match_groups) # check if the keyword found is present in replacements and is a string if (match_groups[0] in replacements and isinstance(replacements[match_groups[0]], str)) : # it is - # build the new_string + # build the replacement string new_string = replacements[match_groups[0]] else : # it isn't # replace the keyword with an empty string new_string = "" - # check if this match has a multiplier - if (match_groups[1] == None) : - # it doesn't - keyword = match_groups[0] - else : - # it does - keyword = match_groups[0] + "{" + match_groups[1] + "}" - new_string *= int(match_groups[1]) + # check if there is any other information provided + if (len(new_string) > 0 and match_count > 1) : + # there is + # loop through the remaining matches + i = 1 + while (i < match_count): + # check if this match is a multiplier + if (match_groups[i].startswith("{") and match_groups[i].endswith("}")) : + # it is + # update the replacement string + new_string *= int(match_groups[i][1:-1]) + # check if this match is a case enforcer + elif (match_groups[i].startswith("[") and match_groups[i].endswith("]")) : + # it is + # check if this case enforcer is valid + case_enforcer = match_groups[i][1:-1].lower() + if (case_enforcer in str_func) : + # it is + # update the replacement string + new_string = getattr(new_string, str_func[case_enforcer], new_string)() + + i += 1 # replace the keyword with the new_string - string = string.replace("|!" + keyword + "!|", new_string) + string = string.replace("|!" + "".join(match_groups) + "!|", new_string) # check the pattern again re_matches = re.search(re_pattern, string) diff --git a/classes/CLI.py b/classes/CLI.py index 75c8094..e428357 100644 --- a/classes/CLI.py +++ b/classes/CLI.py @@ -1,6 +1,6 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Python Project Manager v1.2.1 # +# Python Project Manager v1.3.0 # # # # Copyright 2016, PedroHenriques # # http://www.pedrojhenriques.com # @@ -130,7 +130,10 @@ def processHelp(self) : # store the necessary arguments # desired topic, if 1 was given, or None otherwise - self.args["topic"] = sys.argv[2] if (len(sys.argv) > 2) else None + if (len(sys.argv) > 2) : + self.args["topic"] = sys.argv[2] + else : + self.args["topic"] = None # all OK return(True) diff --git a/classes/__init__.py b/classes/__init__.py index 83c18f5..cf6189a 100644 --- a/classes/__init__.py +++ b/classes/__init__.py @@ -1,6 +1,6 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Python Project Manager v1.2.1 # +# Python Project Manager v1.3.0 # # # # Copyright 2016, PedroHenriques # # http://www.pedrojhenriques.com # diff --git a/data/file.json b/data/file.json index 56c8a7e..f3830a4 100644 --- a/data/file.json +++ b/data/file.json @@ -1,24 +1,50 @@ { "php" : { + "blank" : { + "extension" : "php", + "content" : "" + }, "class" : { "extension" : "php", - "content" : "" + "content" : "" }, "ajax" : { "extension" : "php", - "content" : "" + "content" : "" } }, "ruby" : { + "blank" : { + "extension" : "rb", + "content" : "|!copyright!|\n\n" + }, "class" : { "extension" : "rb", - "content" : "|!copyright!|\n\nclass |!file_name!|\n\tdef initialize()\n\tend" + "content" : "|!copyright!|\n\nclass |!file_name[t]!|\n\tdef initialize()\n\tend" } }, "python" : { + "blank" : { + "extension" : "py", + "content" : "|!copyright!|\n\n" + }, "class" : { "extension" : "py", - "content" : "|!copyright!|\n\nclass |!file_name!| :\n\t\"\"\"String with class information\"\"\"\n\n\tdef __init__(self) :\n\t\tpass" + "content" : "|!copyright!|\n\nclass |!file_name[t]!| :\n\t\"\"\"String with class information\"\"\"\n\n\tdef __init__(self) :\n\t\tpass" + } + }, + "cpp" : { + "blank" : { + "extension" : "cpp", + "content" : "|!copyright!|\n\n" + }, + "class" : { + "extension" : "cpp", + "content" : "|!copyright!|\n\n#include \"|!file_name[t]!|.h\"\n\n|!file_name[t]!|::|!file_name[t]!|() {}\n\n|!file_name[t]!|::~|!file_name[t]!|() {}" + }, + "header" : { + "extension" : "h", + "content" : "|!copyright!|\n\n// include guard: |!file_name[uc]!|_H\n#ifndef |!file_name[uc]!|_H\n#define |!file_name[uc]!|_H\n\n// includes\n\n// class definition\nclass |!file_name[t]!| {\n\tpublic:\n\t\t|!file_name[t]!|();\n\t\t~|!file_name[t]!|();};\n\n// include guard: |!file_name[uc]!|_H\n#endif" } }, "css" : { diff --git a/data/help.json b/data/help.json index fd7cc9e..4915018 100644 --- a/data/help.json +++ b/data/help.json @@ -1,4 +1,10 @@ { - "project" : "=> Creates a new project. The command syntax is:\n\tproject path name type\n- path is the path, relative to the current directory, where the project should be created. Use a fullstop if the current directory is the desired path.\n- name is the project's directory name\n- type is the type of the project, as defined in \"project.json\". Use : to separate JSON tiers.", - "file" : "=> Creates a new file. The command syntax is:\n\tfile path name type [-flags]\n- path is the path, relative to the current directory, where the file should be created. Use a fullstop if the current directory is the desired path.\n- name is the file's name (without the extension).\n- type is the type of the file, as defined in \"file.json\". Use : to separate JSON tiers.\n- [-flags] is an optional argument where configuration flags can be provided. The supported flags are:\n\tf = force the creation of the file by creating any directories in the path that don't exist.\n\to = if a file with the same path already exists, it will be overwritten." + "project" : { + "base" : "=> Creates a new project. The command syntax is:\n\tproject path name type\n- path is the path, relative to the current directory, where the project should be created. Use a fullstop if the current directory is the desired path.\n- name is the project's directory name\n- type is the type of the project, as defined in \"project.json\". Type \"help project:type\" for a list of supported project types.", + "type" : "=> The project types supported by this program are:" + }, + "file" : { + "base" : "=> Creates a new file. The command syntax is:\n\tfile path name type [-flags]\n- path is the path, relative to the current directory, where the file should be created. Use a fullstop if the current directory is the desired path.\n- name is the file's name (without the extension).\n- type is the type of the file, as defined in \"file.json\". Type \"help file:type\" for a list of supported file types.\n- [-flags] is an optional argument where configuration flags can be provided. The supported flags are:\n\tf = force the creation of the file by creating any directories in the path that don't exist.\n\to = if a file with the same path already exists, it will be overwritten.", + "type" : "=> The file types supported by this program are:" + } } diff --git a/data/keywords.json b/data/keywords.json index 2b67738..c1aac86 100644 --- a/data/keywords.json +++ b/data/keywords.json @@ -8,7 +8,9 @@ "js" : {"start" : "/*!!", "end" : "*/", "char" : "*"}, "scss" : {"start" : "/*!!", "end" : "*/", "char" : "*"}, "rb" : {"start" : "#", "end" : "#", "char" : "#"}, - "py" : {"start" : "#", "end" : "#", "char" : "#"} + "py" : {"start" : "#", "end" : "#", "char" : "#"}, + "cpp" : {"start" : "/*", "end" : "*/", "char" : "*"}, + "h" : {"start" : "/*", "end" : "*/", "char" : "*"} } } } diff --git a/data/project.json b/data/project.json index 9cf0b76..fb884e1 100644 --- a/data/project.json +++ b/data/project.json @@ -1,5 +1,5 @@ { - "website" : { + "php" : { "robots.txt" : "", ".gitignore" : "vendor/\n.sass-cache/\nmain.css.map\nimages/\n_extra/", "assets" : { @@ -20,13 +20,13 @@ "ajax_files" : {}, "aux_pages" : {}, "classes" : { - "DB.php" : "pdo_obj = new PDO(\"mysql:host=localhost;dbname=\".self::$db_name, self::$db_user, self::$db_pw);\n\t\t}catch (PDOException $e) {\n\t\t\t// couldn't connect to DB\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// returns the DB connection\n\t// if one doesn't exist, then a connection will be created\n\tpublic static function getInstance() {\n\t\t// if a DB connection hasn't been created\n\t\tif (self::$instance == null) {\n\t\t\t// create a DB instance and store it\n\t\t\t$new_instance = new self;\n\n\t\t\t// if an instance was successfuly created, store it\n\t\t\tif ($new_instance->pdo_obj !== null) {\n\t\t\t\tself::$instance = $new_instance;\n\t\t\t}\n\t\t}\n\n\t\treturn(self::$instance);\n\t}\n\n\t// begins a transaction\n\t// returns True if successful or False otherwise\n\tpublic function beginTransaction() {\n\t\ttry {\n\t\t\treturn((bool)$this->pdo_obj->beginTransaction());\n\t\t}catch (PDOException $e) {\n\t\t\treturn(false);\n\t\t}\n\t}\n\n\t// commits a transaction\n\t// returns True if successful or False otherwise\n\tpublic function commit() {\n\t\ttry {\n\t\t\t// check if there is an open transaction\n\t\t\tif (!(bool)$this->pdo_obj->inTransaction()) {\n\t\t\t\t// there isn't an open transition\n\t\t\t\treturn(true);\n\t\t\t}\n\n\t\t\treturn((bool)$this->pdo_obj->commit());\n\t\t}catch (PDOException $e) {\n\t\t\treturn(false);\n\t\t}\n\t}\n\n\t// rollback a transaction\n\t// returns True if successful or False otherwise\n\tpublic function rollBack() {\n\t\ttry {\n\t\t\t// check if there is an open transaction\n\t\t\tif (!(bool)$this->pdo_obj->inTransaction()) {\n\t\t\t\t// there isn't an open transition\n\t\t\t\treturn(true);\n\t\t\t}\n\n\t\t\treturn((bool)$this->pdo_obj->rollBack());\n\t\t}catch (PDOException $e) {\n\t\t\treturn(false);\n\t\t}\n\t}\n\n\t// prepares and runs a SELECT query\n\t// returns all query's results, as an assoc array\n\tpublic function querySelect($query, array $input_params) {\n\t\ttry {\n\t\t\t// prepare the query\n\t\t\t$pdo_statement = $this->pdo_obj->prepare($query);\n\n\t\t\tif ($pdo_statement === false) {\n\t\t\t\t// the query couldn't be prepared\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// execute the query\n\t\t\tif (!$pdo_statement->execute($input_params)) {\n\t\t\t\t// the query couldn't be executed\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// check if a game was found\n\t\t\tif ($pdo_statement->rowCount() === 0) {\n\t\t\t\t// it wasn't\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// fetch the results\n\t\t\t$pdo_results = $pdo_statement->fetchAll(PDO::FETCH_ASSOC);\n\n\t\t\tif ($pdo_results === false) {\n\t\t\t\t// failed to fetch results\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// at this point everything should have gone OK\n\t\t\treturn($pdo_results);\n\t\t}catch (PDOException $e) {\n\t\t\treturn([]);\n\t\t}\n\t}\n\n\t// prepares and runs an INSERT query\n\t// returns the IDs of the inserted rows\n\tpublic function queryInsert($query, array $input_params) {\n\t\ttry {\n\t\t\t// prepare the query\n\t\t\t$pdo_statement = $this->pdo_obj->prepare($query);\n\n\t\t\tif ($pdo_statement === false) {\n\t\t\t\t// the query couldn't be prepared\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// stores the inserted IDs\n\t\t\t$inserted_ids = [];\n\n\t\t\t// loop through each $input_params element\n\t\t\tforeach ($input_params as $params) {\n\t\t\t\t// execute the query\n\t\t\t\tif (!$pdo_statement->execute($params)) {\n\t\t\t\t\t// the query couldn't be executed\n\t\t\t\t\t$inserted_ids[] = null;\n\t\t\t\t}\n\n\t\t\t\t// store the inserted ID\n\t\t\t\t$inserted_ids[] = $this->pdo_obj->lastInsertId();\n\t\t\t}\n\n\t\t\t// return the inserted IDs\n\t\t\treturn($inserted_ids);\n\t\t}catch (PDOException $e) {\n\t\t\treturn([]);\n\t\t}\n\t}\n\n\t// prepares and runs an UPDATE query\n\t// returns the number of updated rows\n\tpublic function queryUpdate($query, array $input_params) {\n\t\ttry {\n\t\t\t// prepare the query\n\t\t\t$pdo_statement = $this->pdo_obj->prepare($query);\n\n\t\t\tif ($pdo_statement === false) {\n\t\t\t\t// the query couldn't be prepared\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// stores the number of updated rows\n\t\t\t$num_updated_rows = 0;\n\n\t\t\t// loop through each $input_params element\n\t\t\tforeach ($input_params as $params) {\n\t\t\t\t// execute the query\n\t\t\t\tif ($pdo_statement->execute($params)) {\n\t\t\t\t\t// the query was executed\n\t\t\t\t\t$num_updated_rows++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// return the number of updated rows\n\t\t\treturn($num_updated_rows);\n\t\t}catch (PDOException $e) {\n\t\t\treturn([]);\n\t\t}\n\t}\n}\n\n?>", - "General.php" : "" + "DB.php" : "pdo_obj = new PDO(\"mysql:host=localhost;dbname=\".self::$db_name, self::$db_user, self::$db_pw);\n\t\t}catch (PDOException $e) {\n\t\t\t// couldn't connect to DB\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// returns the DB connection\n\t// if one doesn't exist, then a connection will be created\n\tpublic static function getInstance() {\n\t\t// if a DB connection hasn't been created\n\t\tif (self::$instance == null) {\n\t\t\t// create a DB instance and store it\n\t\t\t$new_instance = new self;\n\n\t\t\t// if an instance was successfuly created, store it\n\t\t\tif ($new_instance->pdo_obj !== null) {\n\t\t\t\tself::$instance = $new_instance;\n\t\t\t}\n\t\t}\n\n\t\treturn(self::$instance);\n\t}\n\n\t// begins a transaction\n\t// returns True if successful or False otherwise\n\tpublic function beginTransaction() {\n\t\ttry {\n\t\t\treturn((bool)$this->pdo_obj->beginTransaction());\n\t\t}catch (PDOException $e) {\n\t\t\treturn(false);\n\t\t}\n\t}\n\n\t// commits a transaction\n\t// returns True if successful or False otherwise\n\tpublic function commit() {\n\t\ttry {\n\t\t\t// check if there is an open transaction\n\t\t\tif (!(bool)$this->pdo_obj->inTransaction()) {\n\t\t\t\t// there isn't an open transition\n\t\t\t\treturn(true);\n\t\t\t}\n\n\t\t\treturn((bool)$this->pdo_obj->commit());\n\t\t}catch (PDOException $e) {\n\t\t\treturn(false);\n\t\t}\n\t}\n\n\t// rollback a transaction\n\t// returns True if successful or False otherwise\n\tpublic function rollBack() {\n\t\ttry {\n\t\t\t// check if there is an open transaction\n\t\t\tif (!(bool)$this->pdo_obj->inTransaction()) {\n\t\t\t\t// there isn't an open transition\n\t\t\t\treturn(true);\n\t\t\t}\n\n\t\t\treturn((bool)$this->pdo_obj->rollBack());\n\t\t}catch (PDOException $e) {\n\t\t\treturn(false);\n\t\t}\n\t}\n\n\t// prepares and runs a SELECT query\n\t// returns all query's results, as an assoc array\n\t// NOTE: this is ONLY for SELECT queries\n\t// NOTE: only runs the query for 1 set of $input_params\n\tpublic function querySelect($query, array $input_params, array $param_types) {\n\t\t// make the query into a 1 line string\n\t\t$query = trim(preg_replace(\"/\\r|\\n|\\t/\", \" \", $query));\n\n\t\t// sanity check\n\t\tif ($query === \"\" || preg_match(\"/^SELECT[ ]+/i\", $query) !== 1 || (empty($input_params) && !empty($param_types)) || (!empty($input_params) && empty($param_types))) {\n\t\t\treturn([]);\n\t\t}\n\n\t\ttry {\n\t\t\t// prepare the query\n\t\t\t$pdo_statement = $this->pdo_obj->prepare($query);\n\n\t\t\tif ($pdo_statement === false) {\n\t\t\t\t// the query couldn't be prepared\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// check if the #values in $input_params matches the #values in $param_types\n\t\t\tif (count($input_params) !== count($param_types)) {\n\t\t\t\t// they don't\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// bind the params\n\t\t\t$params_bound = true;\n\t\t\tfor ($i = 0; $i < count($input_params); $i++) {\n\t\t\t\tif (!$pdo_statement->bindValue($i + 1, $input_params[$i], $param_types[$i])) {\n\t\t\t\t\t// the bind param failled\n\t\t\t\t\t$params_bound = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// execute the query\n\t\t\tif (!$params_bound || !$pdo_statement->execute()) {\n\t\t\t\t// the query couldn't be executed\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// check if data was found\n\t\t\tif ($pdo_statement->rowCount() === 0) {\n\t\t\t\t// it wasn't\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// fetch the results\n\t\t\t$pdo_results = $pdo_statement->fetchAll(PDO::FETCH_ASSOC);\n\n\t\t\tif ($pdo_results === false) {\n\t\t\t\t// failed to fetch results\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// at this point everything should have gone OK\n\t\t\treturn($pdo_results);\n\t\t}catch (PDOException $e) {\n\t\t\treturn([]);\n\t\t}\n\t}\n\n\t// prepares and runs a query\n\t// returns the IDs of the inserted rows, in order the queries where executed\n\t// with NULL in the indexes of the ones that failled\n\t// NOTE: this is NOT for SELECT queries\n\tpublic function queryDetailed($query, array $input_params, array $param_types) {\n\t\t// make the query into a 1 line string\n\t\t$query = trim(preg_replace(\"/\\r|\\n|\\t/\", \" \", $query));\n\n\t\t// sanity check\n\t\tif ($query === \"\" || preg_match(\"/^SELECT[ ]+/i\", $query) !== 0 || empty($input_params) || empty($param_types)) {\n\t\t\treturn([]);\n\t\t}\n\n\t\ttry {\n\t\t\t// prepare the query\n\t\t\t$pdo_statement = $this->pdo_obj->prepare($query);\n\n\t\t\tif ($pdo_statement === false) {\n\t\t\t\t// the query couldn't be prepared\n\t\t\t\treturn([]);\n\t\t\t}\n\n\t\t\t// stores the inserted IDs\n\t\t\t$inserted_ids = [];\n\n\t\t\t// loop through each $input_params element\n\t\t\tforeach ($input_params as $params_row) {\n\t\t\t\t// check if the #values in $input_params matches the #values in $param_types\n\t\t\t\t$params_bound = true;\n\t\t\t\tif (count($params_row) === count($param_types)) {\n\t\t\t\t\t// they do\n\t\t\t\t\t// bind the params\n\t\t\t\t\tfor ($i = 0; $i < count($params_row); $i++) {\n\t\t\t\t\t\t\tif (!$pdo_statement->bindValue($i + 1, $params_row[$i], $param_types[$i])) {\n\t\t\t\t\t\t\t// the bind param failled\n\t\t\t\t\t\t\t$params_bound = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\t// they don't\n\t\t\t\t\t$params_bound = false;\n\t\t\t\t}\n\n\t\t\t\t// execute the query\n\t\t\t\tif ($params_bound && $pdo_statement->execute()) {\n\t\t\t\t\t// succcess, so store the inserted ID\n\t\t\t\t\t$inserted_ids[] = $this->pdo_obj->lastInsertId();\n\t\t\t\t}else{\n\t\t\t\t\t// the query couldn't be executed\n\t\t\t\t\t$inserted_ids[] = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// return the inserted IDs\n\t\t\treturn($inserted_ids);\n\t\t}catch (PDOException $e) {\n\t\t\treturn([]);\n\t\t}\n\t}\n\n\t// prepares and runs a query\n\t// returns the number of affected rows\n\t// NOTE: this is NOT for SELECT queries\n\tpublic function querySimple($query, array $input_params, array $param_types) {\n\t\t// make the query into a 1 line string\n\t\t$query = trim(preg_replace(\"/\\r|\\n|\\t/\", \" \", $query));\n\n\t\t// sanity check\n\t\tif ($query === \"\" || preg_match(\"/^SELECT[ ]+/i\", $query) !== 0 || empty($input_params) || empty($param_types)) {\n\t\t\treturn([]);\n\t\t}\n\n\t\t// used to control some querky behavior of the rowCount() function\n\t\t$max_row_count = null;\n\n\t\t// check if the query is \"SELECT INTO ... ON DUPLICATE KEY UPDATE ...\"\n\t\tif (preg_match(\"/^insert[ ]+into[ ]+.+[ ]+on[ ]+duplicate[ ]+key[ ]+update/i\", $query) === 1) {\n\t\t\t// this type of query will return 2 for each affected row, when in fact it's just 1 affected row\n\t\t\t$max_row_count = 1;\n\t\t}\n\n\t\ttry {\n\t\t\t// prepare the query\n\t\t\t$pdo_statement = $this->pdo_obj->prepare($query);\n\n\t\t\tif ($pdo_statement === false) {\n\t\t\t\t// the query couldn't be prepared\n\t\t\t\treturn(0);\n\t\t\t}\n\n\t\t\t// stores the number of updated rows\n\t\t\t$num_affected_rows = 0;\n\n\t\t\t// loop through each $input_params element\n\t\t\tforeach ($input_params as $params_row) {\n\t\t\t\t// check if the #values in $input_params matches the #values in $param_types\n\t\t\t\t$params_bound = true;\n\t\t\t\tif (count($params_row) === count($param_types)) {\n\t\t\t\t\t// they do\n\t\t\t\t\t// bind the params\n\t\t\t\t\tfor ($i = 0; $i < count($params_row); $i++) {\n\t\t\t\t\t\tif (!$pdo_statement->bindValue($i + 1, $params_row[$i], $param_types[$i])) {\n\t\t\t\t\t\t\t// the bind param failled\n\t\t\t\t\t\t\t$params_bound = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\t// they don't\n\t\t\t\t\t$params_bound = false;\n\t\t\t\t}\n\n\t\t\t\t// execute the query\n\t\t\t\tif ($params_bound && $pdo_statement->execute()) {\n\t\t\t\t\t// the query was executed\n\t\t\t\t\t// check if there is any max to the rowCount() return value\n\t\t\t\t\tif ($max_row_count === null) {\n\t\t\t\t\t\t// there isn't\n\t\t\t\t\t\t$num_affected_rows += $pdo_statement->rowCount();\n\t\t\t\t\t}else{\n\t\t\t\t\t\t// there is\n\t\t\t\t\t\t$num_affected_rows += min($pdo_statement->rowCount(), $max_row_count);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// return the number of updated rows\n\t\t\treturn($num_affected_rows);\n\t\t}catch (PDOException $e) {\n\t\t\treturn(0);\n\t\t}\n\t}\n}\n\n?>", + "General.php" : "" }, "interfaces" : {}, "languages" : {}, "templates" : { - "init.php" : "", - "header.php" : "\n\n\n\n\n\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\n\t\t\n\n\t\t\n\t\t\n\t\t\n\n\t\t\n\t\n\n\t", + "init.php" : "", + "header.php" : "\n\n\n\n\n\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\n\t\t\n\n\t\t\n\t\t\n\t\t\n\n\t\t\n\t\n\n\t", "footer.php" : "\n\t\t\n\t\t\n\t\n\n" }, - "index.php" : "\n\n
\n\t\n
\n\n", + "index.php" : "\n\n
\n\t\n
\n\n", ".htaccess" : "Options +FollowSymlinks\nRewriteEngine on\n\n#\n# no WWW rule\n#\n\nRewriteCond %{HTTP_HOST} ^|!no_www_domain!| [NC]\nRewriteRule ^(.*)$ http://www.|!no_www_domain!|/$1 [L,R=302]" } } @@ -65,7 +65,7 @@ "main.py" : "|!copyright!|\n\nimport traceback\nfrom classes import Application\n\n# code that starts the entire application\ntry :\n\t# instantiate the application's main class\n\tapp = Application()\nexcept Exception as e :\n\ttraceback.print_exc()\n\tprint(\"\\n\")", "classes" : { "__init__.py" : "|!copyright!|\n\nimport os\n\n# list with the files to be imported when \"from package import *\" is called\n__all__ = []\n\n# grab the list of contents in this directory\ndir_path = os.path.dirname(os.path.realpath(__file__))\ndir_contents = os.listdir(dir_path)\n\n# find all the python files\nfor item in dir_contents :\n\t# ignore this file\n\tif (item == \"__init__.py\") :\n\t\tcontinue\n\n\t# check if this item is a file\n\tif (not os.path.isfile(dir_path + \"\\\\\" + item)) :\n\t\t# it's not a file, so ignore\n\t\tcontinue\n\n\t# check if it's a python file\n\tif (not item.endswith(\".py\")) :\n\t\t# it isn't, so ignore\n\t\tcontinue\n\n\t# at this point this item is a python file, so add it to __all__\n\t# not including the \".py\"\n\t__all__.append(item[:-3])", - "Application.py" : "|!copyright!|\n\nclass Application :\n\t\"\"\"This is the application's main class.\"\"\"\n\n\tdef __init__(self) :\n\t\tpass" + "Application.py" : "|!copyright!|\n\nclass |!file_name[t]!| :\n\t\"\"\"This is the application's main class.\"\"\"\n\n\tdef __init__(self) :\n\t\tpass" }, "data" : {} } diff --git a/main.py b/main.py index b254d48..a54b899 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Python Project Manager v1.2.1 # +# Python Project Manager v1.3.0 # # # # Copyright 2016, PedroHenriques # # http://www.pedrojhenriques.com #