From c7ce65d2a2a14d734d9eefc54e3a63ca2357f2d9 Mon Sep 17 00:00:00 2001 From: zlg Date: Mon, 25 Jun 2018 22:22:28 -0700 Subject: Reorganize project --- LICENSE | 7 ++++++ TODO | 2 -- dupekill | 77 ++++++++++++++++++++++++++++------------------------------------ 3 files changed, 41 insertions(+), 45 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3afa8d5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +This program is free software. It comes without any warranty, to the extent +permitted by applicable law. diff --git a/TODO b/TODO index 81cd368..cbbeb7c 100644 --- a/TODO +++ b/TODO @@ -1,3 +1 @@ -dupekill --------- * Find a way to indicate which file a dupe is a copy of. diff --git a/dupekill b/dupekill index 19d9123..e8521ac 100755 --- a/dupekill +++ b/dupekill @@ -6,33 +6,14 @@ import stat from optparse import OptionParser # dupekill - deletes duplicates of existing data -# version 1.2 -# written by zlg -# and NF -# -# licensed under the... -# -# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -# Version 2, December 2004 -# -# Copyright (C) 2004 Sam Hocevar -# 14 rue de Plaisance, 75014 Paris, France -# Everyone is permitted to copy and distribute verbatim or modified -# copies of this license document, and changing it is allowed as long -# as the name is changed. -# -# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -# -# 0. You just DO WHAT THE FUCK YOU WANT TO. -# -# This program is free software. It comes without any warranty, to -# the extent permitted by applicable law. -# -# You have been warned. >:3 +# Version 1.4 (2012-04-02) +# Written by zlg +# Original idea and code by NF +# License: WTFPL # This function determines whether or not the file needs to be added # to the list of files in the data list. + def need_to_add(filepath, datalist): found = 0 if len(datalist) == 0: @@ -44,7 +25,11 @@ def need_to_add(filepath, datalist): return found != 1 -def dupekill(dry_run=False, recursive=False, verbose=False, all_files=False, path=os.getcwd()): +def dupekill(dry_run=False, recursive=False, verbose=False, all_files=False, ignore_links=False, path=os.getcwd()): + + if all_files and verbose: + print("Error: All operations (-a) or only important ones (-v), not both.") + sys.exit(1) if not os.path.isdir(path): print("Error: Unable to fetch directory to work with.") @@ -76,31 +61,33 @@ def dupekill(dry_run=False, recursive=False, verbose=False, all_files=False, pat # Check for information. If we can't fetch any, there's likely # a dead symlink or something else wrong. try: - filesize = os.stat(filepath).st_size + filesize = os.lstat(filepath).st_size # This occurs when the data points to something that can't be found or # resolved. except IOError: - if verbose: + if verbose or all_files: print("NOT FOUND:", filepath) - raise - break + continue # This occurs mostly with symlinks. except OSError: - if verbose: + if verbose or all_files: print("DEAD LINK:", filepath) - raise - break + continue + + if ignore_links: + if os.lstat(filepath).st_mode == 41471: + continue deleted = False # We need this flag to determine state before adding to the list if not os.access(filepath, os.R_OK): - if verbose: + if verbose or all_files: print("NOTICE: Cannot read from", filepath) - break + continue if not os.access(filepath, os.W_OK): - if verbose: + if verbose or all_files: print("NOTICE: Cannot write to", filepath) # Funny, processed_files will always equal the index of the file @@ -138,7 +125,7 @@ def dupekill(dry_run=False, recursive=False, verbose=False, all_files=False, pat if not dry_run: os.remove(filepath) - if verbose: + if verbose or all_files: print("DUPE:", filepath) break else: @@ -161,7 +148,7 @@ def dupekill(dry_run=False, recursive=False, verbose=False, all_files=False, pat if not dry_run: os.remove(filepath) - if verbose: + if verbose or all_files: print("DUPE:", filepath) break @@ -182,16 +169,20 @@ def dupekill(dry_run=False, recursive=False, verbose=False, all_files=False, pat if __name__ == '__main__': try: usage = "Usage: %prog [options] {path}" - parser = OptionParser(usage=usage) - parser.add_option("-d", "--dry", dest='dry_run', action='store_true', default=False, help="displays a list of files dupekill will delete if you run it again without this flag") - parser.add_option("-r", "--recursive", dest='recursive', action='store_true', default=False, help="Recurses into all directories below the starting point") - parser.add_option("-v", "--verbose", dest='verbose', action='store_true', default=False, help="Provide more detailed output") - parser.add_option("-a", "--all-files", dest='all_files', action='store_true', default=False, help="Show all processed files, not just dupes and errors") + description = "Deletes files that have duplicate data in them" + epilog = "dupekill likes to munch on files. A lot. By default, symlinks and hardlinks that point to the same file will be deleted. Be careful!" + version = "%prog version 1.5 (2012-04-05)" + parser = OptionParser(usage=usage, description=description, epilog=epilog, version=version) + parser.add_option("-d", "--dry", dest='dry_run', action='store_true', default=False, help="don't delete any files") + parser.add_option("-r", "--recursive", dest='recursive', action='store_true', default=False, help="recurse into all directories below the current directory") + parser.add_option("-v", "--verbose", dest='verbose', action='store_true', default=False, help="provide more detailed output") + parser.add_option("-a", "--all-files", dest='all_files', action='store_true', default=False, help="show all processed files, not just dupes and errors") + parser.add_option("-i", "--ignore-links", dest="ignore_links", action='store_true', default=False, help="don't process symlinks") (options, args) = parser.parse_args() if args and os.path.isdir(args[0]): path = os.path.abspath(args[0]) else: path = os.getcwd() - dupekill(options.dry_run, options.recursive, options.verbose, options.all_files, path) + dupekill(options.dry_run, options.recursive, options.verbose, options.all_files, options.ignore_links, path) except KeyboardInterrupt: print("Aborted") -- cgit v1.2.3-54-g00ecf 61ce7d68fb3942b52ee7a3&follow=1'>cli: change "Status" heading to "Progress"zlg2-36/+40 2018-09-29Bump to 0.3alpha5 for PyPIzlg1-1/+1 2018-09-29cli: Add pretty printing to 'list' commandzlg3-17/+107 Also add the "--width" option to specify the maximum width of the table. 2018-09-08setup.py: Bump to alpha4 for PyPIzlg1-1/+1 2018-09-08cli: add '--raw' option to list commandzlg2-9/+45 Add '--raw' option to the list command, in addition to proper note expansion. Newline characters in notes are escaped to be friendly to scripting. This option may be shortened to '-r' at the user's convenience. In raw output mode, the information is formatted in plain pipe-delimited strings, one line per row: title|system|ownership|progress|notes ownership and progress are printed in their numeric form, consistent with the OWNERSHIP and PROGRESS dictionaries in the vgstash package. An empty notes field will result in a line ending with a pipe and no whitespace following it. 2018-09-08Add remaining filters to vgstash packagezlg1-2/+11 2018-09-04Update LICENSE to match setup.pyzlg1-80/+67 Whoops. 2018-09-03Branch off from master with pytest, tox, clickzlg16-778/+779 This commit is huge, but contains everything needed for a "proper" build system built on pytest + tox and a CLI built with click. For now, this branch will contain all new vgstash development activity until it reaches feature parity with master. The CLI is installed to pip's PATH. Only the 'init', 'add', and 'list' commands work, with only two filters. This is pre-alpha software, and is therefore not stable yet. 2018-03-18Flesh out filter types and ownership statuszlg3-82/+144 It's time for a refactor to a module; the functionality and interface are clashing. 2018-03-18README.mdown: break line correctlyzlg1-1/+1 2018-03-18add 'playlog' list filterzlg2-2/+9 This filter is used to get an idea of which games you're currently playing through, so you can prioritize games to play when you're bored and detect it when you've beaten a game but haven't marked it as such. 2018-03-13Update helpers a bitzlg1-2/+9 At present, user modification is needed to make these seamless. vgup() may need to be axed in favor of telling the user to make an alias. 2018-03-13Make VGSTASH_DB_LOCATION point to a filezlg2-21/+20 It used to point to a directory, which would then look for .vgstash.db. This behavior was kind of backwards and I don't remember why I did it that way. This change gives users more control over where they put their DB. Be sure to update your environment variable if you have it set! 2016-11-18Remove settings from helpers.shZe Libertine Gamer1-5/+0 Sourcing them in .bash_profile screws up login if they're set. 2016-11-15Correct phrasing in README.Ze Libertine Gamer1-4/+4 2016-11-13DerpZe Libertine Gamer1-0/+1 2016-11-03Improve error handling in shell scriptsZe Libertine Gamer4-3/+23 2016-10-24Correct run_again, add recursionZe Libertine Gamer1-0/+4 Loops and functions -- oh my, what a useful combination. :) 2016-10-21Add quotes to correct behavior for arglistZe Libertine Gamer1-1/+1 2016-10-14updater.sh: add recursion, error handlingZe Libertine Gamer1-43/+101 2016-10-14Correct pipe-handling behaviorZe Libertine Gamer1-1/+9 2016-10-12Clarify a method to move between platformsZe Libertine Gamer1-2/+5 Also correct a typo.