summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO19
-rw-r--r--PKGBUILD30
-rwxr-xr-xTrash.py170
-rw-r--r--en.po84
-rw-r--r--fr.po76
-rw-r--r--trash.pot75
6 files changed, 454 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..15d5914c9cfa
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,19 @@
+pkgbase = trash-py
+ pkgdesc = A cli trash in python 3
+ pkgver = 1.0
+ pkgrel = 1
+ url = http://www.art-software.fr
+ arch = any
+ license = GPL
+ depends = coreutils
+ depends = gettext
+ depends = python>=3.4
+ source = Trash.py
+ source = en.po
+ source = fr.po
+ md5sums = 4ad5337338eeff9f0e0429c151faaad6
+ md5sums = ded9fa8a6f295d34b11e852c1cd48062
+ md5sums = b1b74c67e04ea5ca142075e8256f562f
+
+pkgname = trash-py
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..ed62d5d45a6a
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,30 @@
+# Maintainer: Adrien Sohier <adrien.sohier@art-software.fr>
+
+pkgname=trash-py
+pkgver=1.0
+pkgrel=1
+pkgdesc='A cli trash in python 3'
+arch=('any')
+url="http://www.art-software.fr"
+license=('GPL')
+depends=('coreutils' 'gettext' 'python>=3.4')
+source=("Trash.py"
+ "en.po"
+ "fr.po")
+
+md5sums=('4ad5337338eeff9f0e0429c151faaad6'
+ 'ded9fa8a6f295d34b11e852c1cd48062'
+ 'b1b74c67e04ea5ca142075e8256f562f')
+
+build() {
+ cd "$srcdir"
+ msgfmt en.po -o en.mo
+ msgfmt fr.po -o fr.mo
+}
+
+package() {
+ cd "$srcdir"
+ install -Dm644 en.mo "$pkgdir/usr/share/locale/en/LC_MESSAGES/trash.mo"
+ install -Dm644 fr.mo "$pkgdir/usr/share/locale/fr/LC_MESSAGES/trash.mo"
+ install -Dm755 Trash.py "$pkgdir/usr/bin/trash"
+}
diff --git a/Trash.py b/Trash.py
new file mode 100755
index 000000000000..54b857e3d958
--- /dev/null
+++ b/Trash.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: foldlevel=0
+
+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("trash")
+
+trashDir = environ["HOME"] + "/.Trash"
+dataDir = trashDir + "/files"
+pathDir = trashDir + "/path"
+
+##### Actions #####
+def putToTrash(files):
+ _id = _getNextId_()
+ for item in files:
+ pathItem = ""
+
+ # Get full item path, without following links (ie trash 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(_("Trashed [{itemId}] {path}").format(path=item, itemId=_id))
+ _id += 1
+
+def listTrash():
+ items = [int(i) for i in listdir(pathDir)]
+ items.sort()
+ itemLen = len("%d" % max(items+[1]))
+ print(_("Total size : %s\n") % _trashSize_()[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 trash.").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 trash.").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 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 trash\n- list:\t\tList trashed items with their id\n- drop:\t\tDrop items from the trash\n- restore:\tRestore items from the trash to their original path\n- gc:\t\tReorder items"))
+
+##### Useful stuff #####
+def _checkTrashDir_():
+ if not isdir(trashDir):
+ mkdir(trashDir, 0o755)
+
+ if not isdir(dataDir):
+ mkdir(dataDir, 0o755)
+
+ if not isdir(pathDir):
+ mkdir(pathDir, 0o755)
+
+def _trashSize_():
+ 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:]
+ _checkTrashDir_()
+
+ while len(args) > 0:
+ arg = args[0]
+ args = args[1:]
+
+ if arg == "put":
+ putToTrash(args)
+ break
+
+ if arg == "list":
+ listTrash()
+ continue
+
+ if arg == "drop":
+ dropItems(args)
+ break
+
+ if arg == "restore":
+ restoreItems(args)
+ break
+
+ if arg == "gc":
+ orderIds()
+ continue
+
+ showHelp()
+ break
diff --git a/en.po b/en.po
new file mode 100644
index 000000000000..4f69e795dd48
--- /dev/null
+++ b/en.po
@@ -0,0 +1,84 @@
+# Trash locale files.
+# Copyright (C) 2015, Art SoftWare
+# This file is distributed under the GNU GPLv2 or above.
+# Adrien Sohier <support@art-software.fr>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: 2.0\n"
+"Report-Msgid-Bugs-To: <support@art-software.fr>\n"
+"POT-Creation-Date: 2015-06-06 18:18+0200\n"
+"PO-Revision-Date: 2015-06-06 18:21+0200\n"
+"Last-Translator: <support@art-software.fr>\n"
+"Language-Team: English\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: Trash.py:41
+#, python-brace-format
+msgid "Trashed [{itemId}] {path}"
+msgstr "Trashed [{itemId}] {path}"
+
+#: Trash.py:48
+#, python-format
+msgid "Total size : %s\n"
+msgstr "Total size : %s\n"
+
+#: Trash.py:68 Trash.py:83
+#, python-brace-format
+msgid "ERR: Item #{itemId} was not found in the trash."
+msgstr "ERR: Item #{itemId} was not found in the trash."
+
+#: Trash.py:76
+#, python-brace-format
+msgid "Dropped [{itemId}] {itemPath}"
+msgstr "Dropped [{itemId}] {itemPath}"
+
+#: Trash.py:92
+#, python-brace-format
+msgid "Restored [{itemId}] {itemPath}"
+msgstr "Restored [{itemId}] {itemPath}"
+
+#: Trash.py:97
+#, python-format
+msgid "Ordering items… %s"
+msgstr "Ordering items… %s"
+
+#: Trash.py:102
+#, python-brace-format
+msgid "\rMoved {old} to {new}"
+msgstr "\rMoved {old} to {new}"
+
+#: Trash.py:105
+#, python-brace-format
+msgid ""
+"\rERR: Item #{itemId} does not exist under {path}, deleting its "
+"metadata"
+msgstr ""
+"\rERR: Item #{itemId} does not exist under {path}, deleting its "
+"metadata"
+
+#: Trash.py:112
+#, python-brace-format
+msgid ""
+"WARNING: {items} item(s) were not found in {place} and cleaned."
+msgstr ""
+"WARNING: {items} item(s) were not found in {place} and cleaned."
+
+#: Trash.py:116
+msgid ""
+"\n"
+"- put:\t\tPut items to trash\n"
+"- list:\t\tList trashed items with their id\n"
+"- drop:\t\tDrop items from the trash\n"
+"- restore:\tRestore items from the trash to their original path\n"
+"- gc:\t\tReorder items"
+msgstr ""
+"\n"
+"- put:\t\tPut items to trash\n"
+"- list:\t\tList trashed items with their id\n"
+"- drop:\t\tDrop items from the trash\n"
+"- restore:\tRestore items from the trash to their original path\n"
+"- gc:\t\tReorder items"
diff --git a/fr.po b/fr.po
new file mode 100644
index 000000000000..caf77d62dd11
--- /dev/null
+++ b/fr.po
@@ -0,0 +1,76 @@
+# Trash locale files.
+# Copyright (C) 2015, Art SoftWare
+# This file is distributed under the GNU GPLv2 or above.
+# Adrien Sohier <support@art-software.fr>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: 2.0\n"
+"Report-Msgid-Bugs-To: <support@art-software.fr>\n"
+"POT-Creation-Date: 2015-06-06 18:18+0200\n"
+"PO-Revision-Date: 2015-06-06 18:22+0200\n"
+"Last-Translator: <support@art-software.fr>\n"
+"Language-Team: French\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: Trash.py:41
+#, python-brace-format
+msgid "Trashed [{itemId}] {path}"
+msgstr "Déplacé [{itemId}] {path} dans la corbeille"
+
+#: Trash.py:48
+#, python-format
+msgid "Total size : %s\n"
+msgstr "Taille totale : %s\n"
+
+#: Trash.py:68 Trash.py:83
+#, python-brace-format
+msgid "ERR: Item #{itemId} was not found in the trash."
+msgstr "ERR: L'élément #{itemId} n'a pas été trouvé dans la Corbeille."
+
+#: Trash.py:76
+#, python-brace-format
+msgid "Dropped [{itemId}] {itemPath}"
+msgstr "[{itemId}] {itemPath} a été abandonné"
+
+#: Trash.py:92
+#, python-brace-format
+msgid "Restored [{itemId}] {itemPath}"
+msgstr "[{itemId}] {itemPath} a été restauré"
+
+#: Trash.py:97
+#, python-format
+msgid "Ordering items… %s"
+msgstr "Arrangement des éléments… %s"
+
+#: Trash.py:102
+#, python-brace-format
+msgid "\rMoved {old} to {new}"
+msgstr "\rDéplacement de {old} vers {new}"
+
+#: Trash.py:105
+#, python-brace-format
+msgid "\rERR: Item #{itemId} does not exist under {path}, deleting its metadata"
+msgstr "\rERR: L'élément #{itemId} n'existe pas dans {path}, suppression de ses métadonnées"
+
+#: Trash.py:112
+#, python-brace-format
+msgid "WARNING: {items} item(s) were not found in {place} and cleaned."
+msgstr "ATTENTION: {items} élément(s) n'ont pas été trouvés dans {place} et nettoyé(s)."
+
+#: Trash.py:116
+msgid "\n"
+"- put:\t\tPut items to trash\n"
+"- list:\t\tList trashed items with their id\n"
+"- drop:\t\tDrop items from the trash\n"
+"- restore:\tRestore items from the trash to their original path\n"
+"- gc:\t\tReorder items"
+msgstr "\n"
+"- put:\t\tMettre les éléments dans la Corbeille\n"
+"- list:\t\tListe les éléments mis en Corbeille avec leur numéro identifiant\n"
+"- drop:\t\tAbandonne des éléments de la Corbeille\n"
+"- restore:\tRestaure des éléments de la Corbeille dans leur emplacement originel\n"
+"- gc:\t\tRéorganise les éléments de la Corbeille"
diff --git a/trash.pot b/trash.pot
new file mode 100644
index 000000000000..bdc73268686d
--- /dev/null
+++ b/trash.pot
@@ -0,0 +1,75 @@
+# Trash locale files.
+# Copyright (C) 2015, Art SoftWare
+# This file is distributed under the GNU GPLv2 or above.
+# Adrien Sohier <support@art-software.fr>, 2015.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: 2.0\n"
+"Report-Msgid-Bugs-To: <support@art-software.fr>\n"
+"POT-Creation-Date: 2015-06-06 18:18+0200\n"
+"PO-Revision-Date: 2015-06-06 18:20+0200\n"
+"Last-Translator: Adrien Sohier <support@art-software.fr>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: Trash.py:41
+#, python-brace-format
+msgid "Trashed [{itemId}] {path}"
+msgstr ""
+
+#: Trash.py:48
+#, python-format
+msgid "Total size : %s\n"
+msgstr ""
+
+#: Trash.py:68 Trash.py:83
+#, python-brace-format
+msgid "ERR: Item #{itemId} was not found in the trash."
+msgstr ""
+
+#: Trash.py:76
+#, python-brace-format
+msgid "Dropped [{itemId}] {itemPath}"
+msgstr ""
+
+#: Trash.py:92
+#, python-brace-format
+msgid "Restored [{itemId}] {itemPath}"
+msgstr ""
+
+#: Trash.py:97
+#, python-format
+msgid "Ordering items… %s"
+msgstr ""
+
+#: Trash.py:102
+#, python-brace-format
+msgid "\rMoved {old} to {new}"
+msgstr ""
+
+#: Trash.py:105
+#, python-brace-format
+msgid ""
+"\rERR: Item #{itemId} does not exist under {path}, deleting its "
+"metadata"
+msgstr ""
+
+#: Trash.py:112
+#, python-brace-format
+msgid ""
+"WARNING: {items} item(s) were not found in {place} and cleaned."
+msgstr ""
+
+#: Trash.py:116
+msgid ""
+"\n"
+"- put:\t\tPut items to trash\n"
+"- list:\t\tList trashed items with their id\n"
+"- drop:\t\tDrop items from the trash\n"
+"- restore:\tRestore items from the trash to their original path\n"
+"- gc:\t\tReorder items"
+msgstr ""