Merge pull request 'Delete packages, arch-repos & repos' (#265) from Chewing_Bever/vieter:repo-delete-routes into dev
	
		
			
	
		
	
	
		
			
				
	
				ci/woodpecker/push/lint Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docs Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/arch Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/man Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/test Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docker Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/deploy Pipeline was successful
				
					Details
				
			
		
	
				
					
				
			
				
	
				ci/woodpecker/push/lint Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docs Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/arch Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/man Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/test Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docker Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/deploy Pipeline was successful
				
					Details
				
			
		
	Reviewed-on: #265remotes/1750864547369437778/tmp_refs/heads/v-0.3.1
						commit
						78b0918df7
					
				|  | @ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| * Targets with kind 'url' can provide a direct URL to a PKGBUILD instead of | ||||
|   providing a Git repository | ||||
| * CLI commands for searching the AUR & directly adding packages | ||||
| * HTTP routes for removing packages, arch-repos & repos | ||||
| 
 | ||||
| ### Changed | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,3 +93,87 @@ other already present arch-repos. | |||
| Parameter | Description | ||||
| --------- | ----------- | ||||
| repo | Repository to publish package to | ||||
| 
 | ||||
| ## Remove package from arch-repo | ||||
| 
 | ||||
| <aside class="notice"> | ||||
| 
 | ||||
| This endpoint requests authentication. | ||||
| 
 | ||||
| </aside> | ||||
| 
 | ||||
| ```shell | ||||
| curl \ | ||||
|   -H 'X-Api-Key: secret' \ | ||||
|   -XDELETE \ | ||||
|   https://example.com/vieter/x86_64/mike | ||||
| ``` | ||||
| 
 | ||||
| This endpoint allows you to remove a package from a given arch-repo. | ||||
| 
 | ||||
| ### HTTP Request | ||||
| 
 | ||||
| `DELETE /:repo/:arch/:pkg` | ||||
| 
 | ||||
| ### URL Parameters | ||||
| 
 | ||||
| Parameter | Description | ||||
| --------- | ----------- | ||||
| repo | Repository to delete package from | ||||
| arch | Specific arch-repo to remove package from | ||||
| pkg | Name of package to remove (without any version information) | ||||
| 
 | ||||
| ## Remove arch-repo | ||||
| 
 | ||||
| <aside class="notice"> | ||||
| 
 | ||||
| This endpoint requests authentication. | ||||
| 
 | ||||
| </aside> | ||||
| 
 | ||||
| ```shell | ||||
| curl \ | ||||
|   -H 'X-Api-Key: secret' \ | ||||
|   -XDELETE \ | ||||
|   https://example.com/vieter/x86_64 | ||||
| ``` | ||||
| 
 | ||||
| This endpoint allows removing an entire arch-repo. | ||||
| 
 | ||||
| ### HTTP Request | ||||
| 
 | ||||
| `DELETE /:repo/:arch` | ||||
| 
 | ||||
| ### URL Parameters | ||||
| 
 | ||||
| Parameter | Description | ||||
| --------- | ----------- | ||||
| repo | Repository to delete arch-repo from | ||||
| arch | Specific architecture to remove | ||||
| 
 | ||||
| ## Remove repo | ||||
| 
 | ||||
| <aside class="notice"> | ||||
| 
 | ||||
| This endpoint requests authentication. | ||||
| 
 | ||||
| </aside> | ||||
| 
 | ||||
| ```shell | ||||
| curl \ | ||||
|   -H 'X-Api-Key: secret' \ | ||||
|   -XDELETE \ | ||||
|   https://example.com/vieter | ||||
| ``` | ||||
| 
 | ||||
| This endpoint allows removing an entire repo. | ||||
| 
 | ||||
| ### HTTP Request | ||||
| 
 | ||||
| `DELETE /:repo` | ||||
| 
 | ||||
| ### URL Parameters | ||||
| 
 | ||||
| Parameter | Description | ||||
| --------- | ----------- | ||||
| repo | Repository to delete | ||||
|  |  | |||
|  | @ -154,51 +154,3 @@ fn (r &RepoGroupManager) add_pkg_in_arch_repo(repo string, arch string, pkg &pac | |||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // remove_pkg_from_arch_repo removes a package from an arch-repo's database. It | ||||
| // returns false if the package wasn't present in the database. It also | ||||
| // optionally re-syncs the repo archives. | ||||
| fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, pkg_name string, sync bool) ?bool { | ||||
| 	repo_dir := os.join_path(r.repos_dir, repo, arch) | ||||
| 
 | ||||
| 	// If the repository doesn't exist yet, the result is automatically false | ||||
| 	if !os.exists(repo_dir) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// We iterate over every directory in the repo dir | ||||
| 	// TODO filter so we only check directories | ||||
| 	for d in os.ls(repo_dir)? { | ||||
| 		// Because a repository only allows a single version of each package, | ||||
| 		// we need only compare whether the name of the package is the same, | ||||
| 		// not the version. | ||||
| 		name := d.split('-')#[..-2].join('-') | ||||
| 
 | ||||
| 		if name == pkg_name { | ||||
| 			// We lock the mutex here to prevent other routines from creating a | ||||
| 			// new archive while we remove an entry | ||||
| 			lock r.mutex { | ||||
| 				os.rmdir_all(os.join_path_single(repo_dir, d))? | ||||
| 			} | ||||
| 
 | ||||
| 			// Also remove the package archive | ||||
| 			repo_pkg_dir := os.join_path(r.pkg_dir, repo, arch) | ||||
| 
 | ||||
| 			archives := os.ls(repo_pkg_dir)?.filter(it.split('-')#[..-3].join('-') == name) | ||||
| 
 | ||||
| 			for archive_name in archives { | ||||
| 				full_path := os.join_path_single(repo_pkg_dir, archive_name) | ||||
| 				os.rm(full_path)? | ||||
| 			} | ||||
| 
 | ||||
| 			// Sync the db archives if requested | ||||
| 			if sync { | ||||
| 				r.sync(repo, arch)? | ||||
| 			} | ||||
| 
 | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
|  | @ -0,0 +1,85 @@ | |||
| module repo | ||||
| 
 | ||||
| import os | ||||
| 
 | ||||
| // remove_pkg_from_arch_repo removes a package from an arch-repo's database. It | ||||
| // returns false if the package wasn't present in the database. It also | ||||
| // optionally re-syncs the repo archives. | ||||
| pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, pkg_name string, sync bool) ?bool { | ||||
| 	repo_dir := os.join_path(r.repos_dir, repo, arch) | ||||
| 
 | ||||
| 	// If the repository doesn't exist yet, the result is automatically false | ||||
| 	if !os.exists(repo_dir) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// We iterate over every directory in the repo dir | ||||
| 	// TODO filter so we only check directories | ||||
| 	for d in os.ls(repo_dir)? { | ||||
| 		// Because a repository only allows a single version of each package, | ||||
| 		// we need only compare whether the name of the package is the same, | ||||
| 		// not the version. | ||||
| 		name := d.split('-')#[..-2].join('-') | ||||
| 
 | ||||
| 		if name == pkg_name { | ||||
| 			// We lock the mutex here to prevent other routines from creating a | ||||
| 			// new archive while we remove an entry | ||||
| 			lock r.mutex { | ||||
| 				os.rmdir_all(os.join_path_single(repo_dir, d))? | ||||
| 			} | ||||
| 
 | ||||
| 			// Also remove the package archive | ||||
| 			repo_pkg_dir := os.join_path(r.pkg_dir, repo, arch) | ||||
| 
 | ||||
| 			archives := os.ls(repo_pkg_dir)?.filter(it.split('-')#[..-3].join('-') == name) | ||||
| 
 | ||||
| 			for archive_name in archives { | ||||
| 				full_path := os.join_path_single(repo_pkg_dir, archive_name) | ||||
| 				os.rm(full_path)? | ||||
| 			} | ||||
| 
 | ||||
| 			// Sync the db archives if requested | ||||
| 			if sync { | ||||
| 				r.sync(repo, arch)? | ||||
| 			} | ||||
| 
 | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // remove_arch_repo removes an arch-repo & its packages. | ||||
| pub fn (r &RepoGroupManager) remove_arch_repo(repo string, arch string) ?bool { | ||||
| 	repo_dir := os.join_path(r.repos_dir, repo, arch) | ||||
| 
 | ||||
| 	// If the repository doesn't exist yet, the result is automatically false | ||||
| 	if !os.exists(repo_dir) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	os.rmdir_all(repo_dir)? | ||||
| 
 | ||||
| 	pkg_dir := os.join_path(r.pkg_dir, repo, arch) | ||||
| 	os.rmdir_all(pkg_dir)? | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // remove_repo removes a repo & its packages. | ||||
| pub fn (r &RepoGroupManager) remove_repo(repo string) ?bool { | ||||
| 	repo_dir := os.join_path_single(r.repos_dir, repo) | ||||
| 
 | ||||
| 	// If the repository doesn't exist yet, the result is automatically false | ||||
| 	if !os.exists(repo_dir) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	os.rmdir_all(repo_dir)? | ||||
| 
 | ||||
| 	pkg_dir := os.join_path_single(r.pkg_dir, repo) | ||||
| 	os.rmdir_all(pkg_dir)? | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
|  | @ -0,0 +1,77 @@ | |||
| module server | ||||
| 
 | ||||
| import web | ||||
| import net.http | ||||
| import response { new_response } | ||||
| 
 | ||||
| // delete_package tries to remove the given package. | ||||
| ['/:repo/:arch/:pkg'; delete] | ||||
| fn (mut app App) delete_package(repo string, arch string, pkg string) web.Result { | ||||
| 	if !app.is_authorized() { | ||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||
| 	} | ||||
| 
 | ||||
| 	res := app.repo.remove_pkg_from_arch_repo(repo, arch, pkg, true) or { | ||||
| 		app.lerror('Error while deleting package: $err.msg()') | ||||
| 
 | ||||
| 		return app.json(http.Status.internal_server_error, new_response('Failed to delete package.')) | ||||
| 	} | ||||
| 
 | ||||
| 	if res { | ||||
| 		app.linfo("Removed package '$pkg' from '$repo/$arch'") | ||||
| 
 | ||||
| 		return app.json(http.Status.ok, new_response('Package removed.')) | ||||
| 	} else { | ||||
| 		app.linfo("Tried removing package '$pkg' from '$repo/$arch', but it doesn't exist.") | ||||
| 
 | ||||
| 		return app.json(http.Status.not_found, new_response('Package not found.')) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // delete_arch_repo tries to remove the given arch-repo. | ||||
| ['/:repo/:arch'; delete] | ||||
| fn (mut app App) delete_arch_repo(repo string, arch string) web.Result { | ||||
| 	if !app.is_authorized() { | ||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||
| 	} | ||||
| 
 | ||||
| 	res := app.repo.remove_arch_repo(repo, arch) or { | ||||
| 		app.lerror('Error while deleting arch-repo: $err.msg()') | ||||
| 
 | ||||
| 		return app.json(http.Status.internal_server_error, new_response('Failed to delete arch-repo.')) | ||||
| 	} | ||||
| 
 | ||||
| 	if res { | ||||
| 		app.linfo("Removed '$repo/$arch'") | ||||
| 
 | ||||
| 		return app.json(http.Status.ok, new_response('Arch-repo removed.')) | ||||
| 	} else { | ||||
| 		app.linfo("Tried removing '$repo/$arch', but it doesn't exist.") | ||||
| 
 | ||||
| 		return app.json(http.Status.not_found, new_response('Arch-repo not found.')) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // delete_repo tries to remove the given repo. | ||||
| ['/:repo'; delete] | ||||
| fn (mut app App) delete_repo(repo string) web.Result { | ||||
| 	if !app.is_authorized() { | ||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||
| 	} | ||||
| 
 | ||||
| 	res := app.repo.remove_repo(repo) or { | ||||
| 		app.lerror('Error while deleting repo: $err.msg()') | ||||
| 
 | ||||
| 		return app.json(http.Status.internal_server_error, new_response('Failed to delete repo.')) | ||||
| 	} | ||||
| 
 | ||||
| 	if res { | ||||
| 		app.linfo("Removed '$repo'") | ||||
| 
 | ||||
| 		return app.json(http.Status.ok, new_response('Repo removed.')) | ||||
| 	} else { | ||||
| 		app.linfo("Tried removing '$repo', but it doesn't exist.") | ||||
| 
 | ||||
| 		return app.json(http.Status.not_found, new_response('Repo not found.')) | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue