summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheCynicalLiger2020-06-18 16:07:26 +0100
committerTheCynicalLiger2020-06-18 16:07:26 +0100
commit534737360a51c694361c705353c3c45765513b14 (patch)
tree972ca748a90501a06878740c3a0a7de5a0798395
downloadaur-534737360a51c694361c705353c3c45765513b14.tar.gz
First Build
-rw-r--r--.SRCINFO15
-rw-r--r--PKGBUILD19
-rwxr-xr-xRecycle.py178
3 files changed, 212 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..cc6d2ae4737a
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,15 @@
+pkgbase = recycle-cli
+ pkgdesc = A recycle bin cli in python 3
+ pkgver = 1.1
+ pkgrel = 1
+ url = https://aur.archlinux.org/packages/recycle-cli/
+ arch = any
+ license = GPL
+ depends = coreutils
+ depends = gettext
+ depends = python>=3.4
+ source = Recycle.py
+ md5sums = 4ad5337338eeff9f0e0429c151faaad6
+
+pkgname = recycle-cli
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..286d731f6a42
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,19 @@
+# Maintainer: TheCynicalTeam <TheCynicalTeam@github.com>
+# Contributor: TheCynicalTeam <TheCynicalTeam@github.com>
+
+pkgname=recycle-cli
+pkgver=1.1
+pkgrel=1
+pkgdesc='A recycle bin cli in python 3'
+arch=('any')
+url="https://aur.archlinux.org/packages/recycle-cli/"
+license=('GPL')
+depends=('coreutils' 'gettext' 'python>=3.4')
+source=("Recycle.py")
+
+md5sums=('4ad5337338eeff9f0e0429c151faaad6')
+
+package() {
+ cd "$srcdir"
+ install -Dm755 Recycle.py "$pkgdir/usr/bin/recycle"
+}
diff --git a/Recycle.py b/Recycle.py
new file mode 100755
index 000000000000..ffff8fd5f38a
--- /dev/null
+++ b/Recycle.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from math import log
+from os import environ, listdir, mkdir, stat, unlink
+from os.path import basename, dirname, exists, isdir, isfile, islink, realpath
+from subprocess import call, getoutput
+from sys import argv
+from time import localtime, strftime
+
+import gettext
+
+gettext.install("recycle")
+
+recycleDir = environ["HOME"] + "/.Trash"
+dataDir = recycleDir + "/files"
+pathDir = recycleDir + "/path"
+
+##### Actions #####
+def putToRecycle(files):
+ _id = _getNextId_()
+ for item in files:
+ pathItem = ""
+
+ # Get full item path, without following links (ie recycle put [link] delete the link, not the link target)
+ if not islink(item):
+ pathItem = realpath(item)
+ else:
+ if dirname(item) == "":
+ item = "./" + item
+ pathItem = realpath(dirname(item)) + "/" + basename(item)
+
+ # FIXME: Find a better way to do this
+ call(['mv', pathItem, dataDir+"/{itemId}".format(itemId=_id)])
+
+ # Write metadata
+ with open(pathDir+"/{itemId}".format(itemId=_id), "w") as f:
+ f.write("{path}".format(path=pathItem))
+
+ print(_("Recycled [{itemId}] {path}").format(path=item, itemId=_id))
+ _id += 1
+
+def listRecycle():
+ items = [int(i) for i in listdir(pathDir)]
+ items.sort()
+ itemLen = len("%d" % max(items+[1]))
+ print(_("Total size : %s\n") % _recycleSize_()[1])
+
+ for item in items:
+ with open(pathDir+"/{itemId}".format(itemId=item), "r") as f:
+ path = f.read().replace("\n", "")
+
+ dataItem = dataDir+"/{itemId}".format(itemId=item)
+ if exists(dataItem) and not islink(dataItem):
+ print("\x1B[1;33m%*d: \x1B[0;32m[%s]\x1B[0m %s" % (itemLen, item, strftime("%F %T", localtime(stat(dataDir+"/{itemId}".format(itemId=item)).st_mtime)), path))
+ elif islink(dataItem):
+ print("\x1B[1;33m%*d: \x1B[0;37m[link]\x1B[0m %s" % (itemLen, item, path))
+ else:
+ print("\x1B[1;33m%*d: \x1B[1;31m[invalid]\x1B[0m %s" % (itemLen, item, path))
+
+def dropItems(ids):
+ for item in ids:
+ path=""
+
+ dataItem = dataDir+"/{itemId}".format(itemId=item)
+ if not exists(dataItem) and not islink(dataItem):
+ print(_("ERR: Item #{itemId} was not found in the recycle.").format(itemId=item))
+
+ if isfile(pathDir+"/{itemId}".format(itemId=item)):
+ with open(pathDir+"/{itemId}".format(itemId=item), "r") as f:
+ path = f.read().replace("\n", "")
+ unlink(pathDir+"/{itemId}".format(itemId=item))
+
+ call(['rm', '-r', '{d}/{item}'.format(d=dataDir, item=item)])
+ print(_("Dropped [{itemId}] {itemPath}").format(itemId=item, itemPath=path))
+
+def restoreItems(ids):
+ for item in ids:
+ path = ""
+ dataItem = dataDir+"/{itemId}".format(itemId=item)
+ if not exists(dataItem) and not islink(dataItem):
+ print(_("ERR: Item #{itemId} was not found in the recycle.").format(itemId=item))
+ continue
+
+ if isfile(pathDir+"/{itemId}".format(itemId=item)):
+ with open(pathDir+"/{itemId}".format(itemId=item), "r") as f:
+ path = f.read().replace("\n", "")
+
+ call(['mv', dataDir+"/{itemId}".format(itemId=item), path])
+ unlink(pathDir+"/{itemId}".format(itemId=item))
+ print(_("Restored [{itemId}] {itemPath}").format(itemId=item, itemPath=path))
+
+def emptyRecycle():
+ call(['rm', '-r', dataDir])
+ call(['rm', '-r', pathDir])
+ _checkRecycleDir_
+
+def orderIds():
+ notFound = 0
+ for num, item in enumerate([int(i) for i in listdir(pathDir)]):
+ print(_("Ordering items… %s") % "|/—\\"[num%4], end="\r")
+
+ dataItem = dataDir+"/{itemId}".format(itemId=item)
+ if exists(dataItem) or islink(dataItem):
+ if num+1 != item:
+ print(_("\rMoved {old} to {new}\x1B[0K").format(old=item, new=num+1))
+ call(['mv', dataDir+"/{itemId}".format(itemId=item), dataDir+"/{itemId}".format(itemId=num+1)])
+ else:
+ print(_("\r\x1B[1;31mERR:\x1B[0m Item #{itemId} does not exist under {path}, deleting its metadata\x1B[0K").format(itemId=item, path=dataDir))
+ unlink(pathDir+"/{itemId}".format(itemId=item))
+ notFound += 1
+ if num+1 != item:
+ call(['mv', pathDir+"/{itemId}".format(itemId=item), pathDir+"/{itemId}".format(itemId=num+1)])
+
+ if notFound > 0:
+ print(_("\x1B[1;33mWARNING:\x1B[0m {items} item(s) were not found in {place} and cleaned.").format(items=notFound, place=dataDir))
+
+def showHelp():
+ print(basename(argv[0])+" [put <path [path [...]]> | list | drop <id [id [...]]> | restore <id [id [...]]> | gc]")
+ print(_("\n- put:\t\tPut items to recycle\n- list:\t\tList recycled items with their id\n- drop:\t\tDrop items from the recycle\n- empty:\tEmpty the recycle.\n- restore:\tRestore items from the recycle to their original path\n- gc:\t\tReorder items"))
+
+##### Useful stuff #####
+def _checkRecycleDir_():
+ if not isdir(recycleDir):
+ mkdir(recycleDir, 0o755)
+
+ if not isdir(dataDir):
+ mkdir(dataDir, 0o755)
+
+ if not isdir(pathDir):
+ mkdir(pathDir, 0o755)
+
+def _recycleSize_():
+ b = int(getoutput('du -sb {path}/'.format(path=dataDir)).split()[0])
+ if b == 0:
+ return (0, "0 B")
+
+ exp = int(log(b, 1024))
+ return (b, "%3.2f %s" % (b/(1024**exp), ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"][exp]))
+
+def _getNextId_():
+ return 1 + max([int(item) for item in listdir(pathDir)]+[0])
+
+##### MAIN #####
+if __name__ == "__main__":
+ args = argv[1:]
+ _checkRecycleDir_()
+
+ while len(args) > 0:
+ arg = args[0]
+ args = args[1:]
+
+ if arg == "empty":
+ emptyRecycle()
+ break
+
+ if arg == "put":
+ putToRecycle(args)
+ break
+
+ if arg == "list":
+ listRecycle()
+ continue
+
+ if arg == "drop":
+ dropItems(args)
+ break
+
+ if arg == "restore":
+ restoreItems(args)
+ break
+
+ if arg == "gc":
+ orderIds()
+ continue
+
+ showHelp()
+ break