prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  invalid package names png++
  Hi,
  
  I try to install some package with the "package" list in the config file, but if i use the package name png++ (i put the link under the message) it return as invalid package names.
  
  https://archlinux.org/packages/community/any/png++/
  
  invalid package names png++
  Hi,
  
  I try to install some package with the "package" list in the config file, but if i use the package name png++ (i put the link under the message) it return as invalid package names.
  
  https://archlinux.org/packages/community/any/png++/
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `archinstall/lib/packages/packages.py`
  Content:
  ```
  1 import json
  2 import ssl
  3 import urllib.request
  4 from typing import Dict, Any, Tuple, List
  5 
  6 from ..exceptions import PackageError, SysCallError
  7 from ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage
  8 from ..pacman import run_pacman
  9 
  10 BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/?name={package}'
  11 # BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/'
  12 BASE_GROUP_URL = 'https://archlinux.org/groups/search/json/?name={group}'
  13 
  14 
  15 def group_search(name :str) -> List[PackageSearchResult]:
  16 	# TODO UPSTREAM: Implement /json/ for the groups search
  17 	ssl_context = ssl.create_default_context()
  18 	ssl_context.check_hostname = False
  19 	ssl_context.verify_mode = ssl.CERT_NONE
  20 	try:
  21 		response = urllib.request.urlopen(BASE_GROUP_URL.format(group=name), context=ssl_context)
  22 	except urllib.error.HTTPError as err:
  23 		if err.code == 404:
  24 			return []
  25 		else:
  26 			raise err
  27 
  28 	# Just to be sure some code didn't slip through the exception
  29 	data = response.read().decode('UTF-8')
  30 
  31 	return [PackageSearchResult(**package) for package in json.loads(data)['results']]
  32 
  33 
  34 def package_search(package :str) -> PackageSearch:
  35 	"""
  36 	Finds a specific package via the package database.
  37 	It makes a simple web-request, which might be a bit slow.
  38 	"""
  39 	# TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ')
  40 	# TODO: utilize pacman cache first, upstream second.
  41 	ssl_context = ssl.create_default_context()
  42 	ssl_context.check_hostname = False
  43 	ssl_context.verify_mode = ssl.CERT_NONE
  44 	response = urllib.request.urlopen(BASE_URL_PKG_SEARCH.format(package=package), context=ssl_context)
  45 
  46 	if response.code != 200:
  47 		raise PackageError(f"Could not locate package: [{response.code}] {response}")
  48 
  49 	data = response.read().decode('UTF-8')
  50 
  51 	return PackageSearch(**json.loads(data))
  52 
  53 
  54 def find_package(package :str) -> List[PackageSearchResult]:
  55 	data = package_search(package)
  56 	results = []
  57 
  58 	for result in data.results:
  59 		if result.pkgname == package:
  60 			results.append(result)
  61 
  62 	# If we didn't find the package in the search results,
  63 	# odds are it's a group package
  64 	if not results:
  65 		# Check if the package is actually a group
  66 		for result in group_search(package):
  67 			results.append(result)
  68 
  69 	return results
  70 
  71 
  72 def find_packages(*names :str) -> Dict[str, Any]:
  73 	"""
  74 	This function returns the search results for many packages.
  75 	The function itself is rather slow, so consider not sending to
  76 	many packages to the search query.
  77 	"""
  78 	result = {}
  79 	for package in names:
  80 		for found_package in find_package(package):
  81 			result[package] = found_package
  82 
  83 	return result
  84 
  85 
  86 def validate_package_list(packages :list) -> Tuple[list, list]:
  87 	"""
  88 	Validates a list of given packages.
  89 	return: Tuple of lists containing valid packavges in the first and invalid
  90 	packages in the second entry
  91 	"""
  92 	valid_packages = {package for package in packages if find_package(package)}
  93 	invalid_packages = set(packages) - valid_packages
  94 
  95 	return list(valid_packages), list(invalid_packages)
  96 
  97 
  98 def installed_package(package :str) -> LocalPackage:
  99 	package_info = {}
  100 	try:
  101 		for line in run_pacman(f"-Q --info {package}"):
  102 			if b':' in line:
  103 				key, value = line.decode().split(':', 1)
  104 				package_info[key.strip().lower().replace(' ', '_')] = value.strip()
  105 	except SysCallError:
  106 		pass
  107 
  108 	return LocalPackage(**package_info)
  109
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/archinstall/lib/packages/packages.py b/archinstall/lib/packages/packages.py
  --- a/archinstall/lib/packages/packages.py
  +++ b/archinstall/lib/packages/packages.py
  @@ -1,25 +1,35 @@
   import json
   import ssl
  -import urllib.request
   from typing import Dict, Any, Tuple, List
  +from urllib.error import HTTPError
  +from urllib.parse import urlencode
  +from urllib.request import urlopen
   
   from ..exceptions import PackageError, SysCallError
   from ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage
   from ..pacman import run_pacman
   
  -BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/?name={package}'
  +BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/'
   # BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/'
  -BASE_GROUP_URL = 'https://archlinux.org/groups/search/json/?name={group}'
  +BASE_GROUP_URL = 'https://archlinux.org/groups/search/json/'
   
   
  -def group_search(name :str) -> List[PackageSearchResult]:
  -	# TODO UPSTREAM: Implement /json/ for the groups search
  +def _make_request(url: str, params: Dict) -> Any:
   	ssl_context = ssl.create_default_context()
   	ssl_context.check_hostname = False
   	ssl_context.verify_mode = ssl.CERT_NONE
  +
  +	encoded = urlencode(params)
  +	full_url = f'{url}?{encoded}'
  +
  +	return urlopen(full_url, context=ssl_context)
  +
  +
  +def group_search(name :str) -> List[PackageSearchResult]:
  +	# TODO UPSTREAM: Implement /json/ for the groups search
   	try:
  -		response = urllib.request.urlopen(BASE_GROUP_URL.format(group=name), context=ssl_context)
  -	except urllib.error.HTTPError as err:
  +		response = _make_request(BASE_GROUP_URL, {'name': name})
  +	except HTTPError as err:
   		if err.code == 404:
   			return []
   		else:
  @@ -38,10 +48,7 @@
   	"""
   	# TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ')
   	# TODO: utilize pacman cache first, upstream second.
  -	ssl_context = ssl.create_default_context()
  -	ssl_context.check_hostname = False
  -	ssl_context.verify_mode = ssl.CERT_NONE
  -	response = urllib.request.urlopen(BASE_URL_PKG_SEARCH.format(package=package), context=ssl_context)
  +	response = _make_request(BASE_URL_PKG_SEARCH, {'name': package})
   
   	if response.code != 200:
   		raise PackageError(f"Could not locate package: [{response.code}] {response}")
  
verification_info: {"golden_diff": "diff --git a/archinstall/lib/packages/packages.py b/archinstall/lib/packages/packages.py\n--- a/archinstall/lib/packages/packages.py\n+++ b/archinstall/lib/packages/packages.py\n@@ -1,25 +1,35 @@\n import json\n import ssl\n-import urllib.request\n from typing import Dict, Any, Tuple, List\n+from urllib.error import HTTPError\n+from urllib.parse import urlencode\n+from urllib.request import urlopen\n \n from ..exceptions import PackageError, SysCallError\n from ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage\n from ..pacman import run_pacman\n \n-BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/?name={package}'\n+BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/'\n # BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/'\n-BASE_GROUP_URL = 'https://archlinux.org/groups/search/json/?name={group}'\n+BASE_GROUP_URL = 'https://archlinux.org/groups/search/json/'\n \n \n-def group_search(name :str) -> List[PackageSearchResult]:\n-\t# TODO UPSTREAM: Implement /json/ for the groups search\n+def _make_request(url: str, params: Dict) -> Any:\n \tssl_context = ssl.create_default_context()\n \tssl_context.check_hostname = False\n \tssl_context.verify_mode = ssl.CERT_NONE\n+\n+\tencoded = urlencode(params)\n+\tfull_url = f'{url}?{encoded}'\n+\n+\treturn urlopen(full_url, context=ssl_context)\n+\n+\n+def group_search(name :str) -> List[PackageSearchResult]:\n+\t# TODO UPSTREAM: Implement /json/ for the groups search\n \ttry:\n-\t\tresponse = urllib.request.urlopen(BASE_GROUP_URL.format(group=name), context=ssl_context)\n-\texcept urllib.error.HTTPError as err:\n+\t\tresponse = _make_request(BASE_GROUP_URL, {'name': name})\n+\texcept HTTPError as err:\n \t\tif err.code == 404:\n \t\t\treturn []\n \t\telse:\n@@ -38,10 +48,7 @@\n \t\"\"\"\n \t# TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ')\n \t# TODO: utilize pacman cache first, upstream second.\n-\tssl_context = ssl.create_default_context()\n-\tssl_context.check_hostname = False\n-\tssl_context.verify_mode = ssl.CERT_NONE\n-\tresponse = urllib.request.urlopen(BASE_URL_PKG_SEARCH.format(package=package), context=ssl_context)\n+\tresponse = _make_request(BASE_URL_PKG_SEARCH, {'name': package})\n \n \tif response.code != 200:\n \t\traise PackageError(f\"Could not locate package: [{response.code}] {response}\")\n", "issue": "invalid package names png++\nHi,\r\n\r\nI try to install some package with the \"package\" list in the config file, but if i use the package name png++ (i put the link under the message) it return as invalid package names.\r\n\r\nhttps://archlinux.org/packages/community/any/png++/\r\n\ninvalid package names png++\nHi,\r\n\r\nI try to install some package with the \"package\" list in the config file, but if i use the package name png++ (i put the link under the message) it return as invalid package names.\r\n\r\nhttps://archlinux.org/packages/community/any/png++/\r\n\n", "before_files": [{"content": "import json\nimport ssl\nimport urllib.request\nfrom typing import Dict, Any, Tuple, List\n\nfrom ..exceptions import PackageError, SysCallError\nfrom ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage\nfrom ..pacman import run_pacman\n\nBASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/?name={package}'\n# BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/'\nBASE_GROUP_URL = 'https://archlinux.org/groups/search/json/?name={group}'\n\n\ndef group_search(name :str) -> List[PackageSearchResult]:\n\t# TODO UPSTREAM: Implement /json/ for the groups search\n\tssl_context = ssl.create_default_context()\n\tssl_context.check_hostname = False\n\tssl_context.verify_mode = ssl.CERT_NONE\n\ttry:\n\t\tresponse = urllib.request.urlopen(BASE_GROUP_URL.format(group=name), context=ssl_context)\n\texcept urllib.error.HTTPError as err:\n\t\tif err.code == 404:\n\t\t\treturn []\n\t\telse:\n\t\t\traise err\n\n\t# Just to be sure some code didn't slip through the exception\n\tdata = response.read().decode('UTF-8')\n\n\treturn [PackageSearchResult(**package) for package in json.loads(data)['results']]\n\n\ndef package_search(package :str) -> PackageSearch:\n\t\"\"\"\n\tFinds a specific package via the package database.\n\tIt makes a simple web-request, which might be a bit slow.\n\t\"\"\"\n\t# TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ')\n\t# TODO: utilize pacman cache first, upstream second.\n\tssl_context = ssl.create_default_context()\n\tssl_context.check_hostname = False\n\tssl_context.verify_mode = ssl.CERT_NONE\n\tresponse = urllib.request.urlopen(BASE_URL_PKG_SEARCH.format(package=package), context=ssl_context)\n\n\tif response.code != 200:\n\t\traise PackageError(f\"Could not locate package: [{response.code}] {response}\")\n\n\tdata = response.read().decode('UTF-8')\n\n\treturn PackageSearch(**json.loads(data))\n\n\ndef find_package(package :str) -> List[PackageSearchResult]:\n\tdata = package_search(package)\n\tresults = []\n\n\tfor result in data.results:\n\t\tif result.pkgname == package:\n\t\t\tresults.append(result)\n\n\t# If we didn't find the package in the search results,\n\t# odds are it's a group package\n\tif not results:\n\t\t# Check if the package is actually a group\n\t\tfor result in group_search(package):\n\t\t\tresults.append(result)\n\n\treturn results\n\n\ndef find_packages(*names :str) -> Dict[str, Any]:\n\t\"\"\"\n\tThis function returns the search results for many packages.\n\tThe function itself is rather slow, so consider not sending to\n\tmany packages to the search query.\n\t\"\"\"\n\tresult = {}\n\tfor package in names:\n\t\tfor found_package in find_package(package):\n\t\t\tresult[package] = found_package\n\n\treturn result\n\n\ndef validate_package_list(packages :list) -> Tuple[list, list]:\n\t\"\"\"\n\tValidates a list of given packages.\n\treturn: Tuple of lists containing valid packavges in the first and invalid\n\tpackages in the second entry\n\t\"\"\"\n\tvalid_packages = {package for package in packages if find_package(package)}\n\tinvalid_packages = set(packages) - valid_packages\n\n\treturn list(valid_packages), list(invalid_packages)\n\n\ndef installed_package(package :str) -> LocalPackage:\n\tpackage_info = {}\n\ttry:\n\t\tfor line in run_pacman(f\"-Q --info {package}\"):\n\t\t\tif b':' in line:\n\t\t\t\tkey, value = line.decode().split(':', 1)\n\t\t\t\tpackage_info[key.strip().lower().replace(' ', '_')] = value.strip()\n\texcept SysCallError:\n\t\tpass\n\n\treturn LocalPackage(**package_info)\n", "path": "archinstall/lib/packages/packages.py"}], "after_files": [{"content": "import json\nimport ssl\nfrom typing import Dict, Any, Tuple, List\nfrom urllib.error import HTTPError\nfrom urllib.parse import urlencode\nfrom urllib.request import urlopen\n\nfrom ..exceptions import PackageError, SysCallError\nfrom ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage\nfrom ..pacman import run_pacman\n\nBASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/'\n# BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/'\nBASE_GROUP_URL = 'https://archlinux.org/groups/search/json/'\n\n\ndef _make_request(url: str, params: Dict) -> Any:\n\tssl_context = ssl.create_default_context()\n\tssl_context.check_hostname = False\n\tssl_context.verify_mode = ssl.CERT_NONE\n\n\tencoded = urlencode(params)\n\tfull_url = f'{url}?{encoded}'\n\n\treturn urlopen(full_url, context=ssl_context)\n\n\ndef group_search(name :str) -> List[PackageSearchResult]:\n\t# TODO UPSTREAM: Implement /json/ for the groups search\n\ttry:\n\t\tresponse = _make_request(BASE_GROUP_URL, {'name': name})\n\texcept HTTPError as err:\n\t\tif err.code == 404:\n\t\t\treturn []\n\t\telse:\n\t\t\traise err\n\n\t# Just to be sure some code didn't slip through the exception\n\tdata = response.read().decode('UTF-8')\n\n\treturn [PackageSearchResult(**package) for package in json.loads(data)['results']]\n\n\ndef package_search(package :str) -> PackageSearch:\n\t\"\"\"\n\tFinds a specific package via the package database.\n\tIt makes a simple web-request, which might be a bit slow.\n\t\"\"\"\n\t# TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ')\n\t# TODO: utilize pacman cache first, upstream second.\n\tresponse = _make_request(BASE_URL_PKG_SEARCH, {'name': package})\n\n\tif response.code != 200:\n\t\traise PackageError(f\"Could not locate package: [{response.code}] {response}\")\n\n\tdata = response.read().decode('UTF-8')\n\n\treturn PackageSearch(**json.loads(data))\n\n\ndef find_package(package :str) -> List[PackageSearchResult]:\n\tdata = package_search(package)\n\tresults = []\n\n\tfor result in data.results:\n\t\tif result.pkgname == package:\n\t\t\tresults.append(result)\n\n\t# If we didn't find the package in the search results,\n\t# odds are it's a group package\n\tif not results:\n\t\t# Check if the package is actually a group\n\t\tfor result in group_search(package):\n\t\t\tresults.append(result)\n\n\treturn results\n\n\ndef find_packages(*names :str) -> Dict[str, Any]:\n\t\"\"\"\n\tThis function returns the search results for many packages.\n\tThe function itself is rather slow, so consider not sending to\n\tmany packages to the search query.\n\t\"\"\"\n\tresult = {}\n\tfor package in names:\n\t\tfor found_package in find_package(package):\n\t\t\tresult[package] = found_package\n\n\treturn result\n\n\ndef validate_package_list(packages :list) -> Tuple[list, list]:\n\t\"\"\"\n\tValidates a list of given packages.\n\treturn: Tuple of lists containing valid packavges in the first and invalid\n\tpackages in the second entry\n\t\"\"\"\n\tvalid_packages = {package for package in packages if find_package(package)}\n\tinvalid_packages = set(packages) - valid_packages\n\n\treturn list(valid_packages), list(invalid_packages)\n\n\ndef installed_package(package :str) -> LocalPackage:\n\tpackage_info = {}\n\ttry:\n\t\tfor line in run_pacman(f\"-Q --info {package}\"):\n\t\t\tif b':' in line:\n\t\t\t\tkey, value = line.decode().split(':', 1)\n\t\t\t\tpackage_info[key.strip().lower().replace(' ', '_')] = value.strip()\n\texcept SysCallError:\n\t\tpass\n\n\treturn LocalPackage(**package_info)\n", "path": "archinstall/lib/packages/packages.py"}]}