#!/usr/bin/perl # apollias-drag-and-drop-pondizer--with-separate-config-file.pl # Version 1.1 # # by Apollia of Astroblahhh.Com. http://astroblahhh.com/ # # # Completed Apr. 28, 2014. # # Released Apr. 29, 2014. # # # Available in this zip file, along with its separate config file: # # http://astroblahhh.com/software/perl/apollias-drag-and-drop-pondizer/v1_1/apollias-drag-and-drop-pondizer-v1_1.zip # # # Web-viewable version: # # http://astroblahhh.com/software/perl/apollias-drag-and-drop-pondizer/v1_1/apollias-drag-and-drop-pondizer--with-separate-config-file-v1_1.txt # # http://astroblahhh.com/software/perl/apollias-drag-and-drop-pondizer/v1_1/Apollias_Drag_and_Drop_Pondizer__Separate_Config_File-v1_1.txt # # # # ################################################################################ # # # Description # # # "Pondize" is a verb I coined which simply means to back up files or folders # to a folder named "Pond". # # On my computer, I like to give my computer folders picturesque, aesthetically # pleasing names which aren't always obviously connected to their actual # purpose. The "Pond" folder is where I like to keep many of my newly-minted # backups. So, anything that goes in the Pond, I say it's been "pondized". # # # This is basically a variant of my zip backup script. This script lets you # drag and drop files/folders onto the script and have them put into either a # zip file in a Pond (or really any folder you want), or into a dated folder # of loose, unzipped files in a Pond (or any folder you want). # # You can provide a prefix and/or suffix for the name of the zip file or # the dated folder. The name of the file or folder can also optionally # contain a (likely abbreviated) list of its contents. # # # You can also configure this script to refuse to run when items are # dragged/dropped onto it or given to this script as command line arguments, # thus making it behave more like the old zip backup script. # # And, you can make it a drag-and-drop only script. # # # As of version 1.1, I figured out how to make this script work with files/folders # with double-quotes (") in their names. # # # For convenience, most of this script's settings are stored in an external # file - Apollias_Drag_and_Drop_Pondizer__Separate_Config_File-v1_1.pl, # which is checked for by default in the same directory as this script. # # Instructions are below and inside # Apollias_Drag_and_Drop_Pondizer__Separate_Config_File-v1_1.pl. # # # ----- # # # Except for parts not by Apollia: # # Copyright (C) 2014 Apollia # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . # # # Contact info: http://astroblahhh.com/contact-apollia.shtml ################################################################ # # Some stuff you should leave alone # # This just gets the script's location. use Cwd 'abs_path'; use File::Basename qw( dirname fileparse ); $this_script_path=abs_path($0); $this_script_parentdirs=dirname( $this_script_path ); print "Running $this_script_path...\n\n\n"; #$escaped_script_path=~s/ /\\ /g; $escaped_script_path=Escape_Quotes($this_script_path); # Makes it possible to use the mkpath function: use File::Path; ################ # # Constants for readability # use constant false => 0; use constant true => 1; # # End of Constants for readability # ################ ################ # # Here, we open an RXVT window so the user can see some output, # and also give input (if this script is configured to accept input). $First_Argv_Arg=$ARGV[0]; if ( $First_Argv_Arg != 1) # If the RXVT window hasn't been opened yet, # then, the first parameter won't be 1. { $all_argv_args = ""; foreach $argv (@ARGV) { $argv=Escape_Quotes($argv); # Escapes quotes $all_argv_args = $all_argv_args . " \"$argv\" "; } @args_for_exec=("rxvt -rv +sb -sl 999 -e perl \"$escaped_script_path\" 1 $all_argv_args"); exec (@args_for_exec); #exec ("rxvt -rv +sb -sl 999 -e perl $escaped_script_path 1 $all_argv_args"); } elsif ( $First_Argv_Arg == 1) { #print @ARGV; @things_to_pondize = @ARGV; shift @things_to_pondize; # Gets rid of the first argv arg - just a 1, # leaving only the paths of the files/folders # that were dragged/dropped onto the script. foreach $thing_to_pondize (@things_to_pondize) { print "$thing_to_pondize \n"; } #End_Script_and_Wait_for_Return(); } # # End of section where we open an RXVT window. # # ################ # End of some stuff you should leave alone # ################################################################ ####################################################################### # # Some stuff you can change, but probably shouldn't # $name_of_separate_config_file = "Apollias_Drag_and_Drop_Pondizer__Separate_Config_File-v1_1.pl"; # This separate file is stored by default in the same directory # as this script itself: $path_to_separate_config_file = $this_script_parentdirs . "/" . $name_of_separate_config_file; # End of some stuff you can change, but probably shouldn't. # ####################################################################### # # Some stuff you can change # # This section is where you can copy/paste the settings from the # separate config file, in case you'd rather have everything all # in one file. # # If you do that, set $should_use_separate_config_file to false. $num_of_seconds_before_autoclose=5; $should_use_separate_config_file=true; # true|false # End of stuff you can change. # # # Below this point, nothing else in this script needs to be changed. # # ####################################################################### ################# # # Start of separate config file stuff if ($should_use_separate_config_file) { if (-e $path_to_separate_config_file) # If the separate config file exists... { print "\n\nFound path to separate config file!\n"; require $path_to_separate_config_file; } else # Couldn't find the separate config file. Can't proceed without it. { print "No separate config file found! Can't proceed.\n"; End_Script_and_Wait_for_Return(); } } # End of separate config file stuff # ################# if ($should_accept_drag_and_drop_items==false) { if (@things_to_pondize) { print "\n\nCurrently configured not to accept drag and dropped items! I assume you didn't actually want to run this script, so, aborting.\n\n"; End_Script_and_Wait_for_Return(); } } if ($should_be_capable_of_running_without_drag_and_drop) { if (!@things_to_pondize) { @things_to_pondize = @things_to_pondize_if_script_is_run_without_drag_and_drop; } } else { if (!@things_to_pondize) { print "\n\nCurrently configured not to do anything if this script is run without drag and dropping items onto it. Aborting.\n\n"; End_Script_and_Wait_for_Return(); } } if (!@things_to_pondize) { print "\n\nNo things to pondize specified! Aborting.\n\n"; End_Script_and_Wait_for_Return(); } if ($should_zip_or_pondize eq "no" || !$should_zip_or_pondize ) { print "\n\nCurrently configured not to do anything!"; End_Script_and_Wait_for_Return(); } $full_path_to_pond = AddSlashIfNeeded($full_path_to_pond); $temp_location_for_pondized_stuff = AddSlashIfNeeded($temp_location_for_pondized_stuff); if ( $should_zip_or_pondize eq "zip") { $action_being_done="zip"; } elsif ( $should_zip_or_pondize eq "pondize") { $action_being_done="pondize"; } if ($should_pondize_to_temp_location_then_copy_to_actual_pond) { $current_parentdirs_of_pondized_stuff=$temp_location_for_pondized_stuff; } else { $current_parentdirs_of_pondized_stuff=$full_path_to_pond; } my @nonexistent_paths; my $count_of_existent_paths=0; #print "current_parentdirs_of_pondized_stuff: $current_parentdirs_of_pondized_stuff "; foreach $thing_to_pondize (@things_to_pondize) { $len=length($thing_to_pondize); #print "thing_to_pondize: $thing_to_pondize "; $second_rightmost_slash_loc=rindex($thing_to_pondize, "/", $len-2); $parentdirs=substr($thing_to_pondize, 0, $second_rightmost_slash_loc+1); $file_or_folder_name=substr($thing_to_pondize, $second_rightmost_slash_loc+1); $length_of_file_or_folder_name=length($file_or_folder_name); if (substr($file_or_folder_name, $length_of_file_or_folder_name-1, 1) eq "/") #If the last character is "/"... { chop($file_or_folder_name); #...get rid of it. } $this_full_path=$parentdirs . $file_or_folder_name; if (!-e $this_full_path) { push (@nonexistent_paths, $this_full_path); } else { $printable_list_of_things_to_pondize=$printable_list_of_things_to_pondize . "$thing_to_pondize\n";; $count_of_existent_paths++; if ($should_add_file_or_folder_names_to_pondize_destination_name ) { $list_of_filesorfols_for_pondize_destination_name = $list_of_filesorfols_for_pondize_destination_name . "$file_or_folder_name; "; } #print "This full path: $this_full_path "; $parentdirs_and_file_or_folder_name{$this_full_path}=[$parentdirs, $file_or_folder_name]; } } if ($should_add_file_or_folder_names_to_pondize_destination_name ) { $list_of_filesorfols_for_pondize_destination_name = substr($list_of_filesorfols_for_pondize_destination_name, 0, -2); } if ($count_of_existent_paths<1) { print "\n\nWarning: No items available to $action_being_done!\n\n"; } else { print "\n\nGoing to try to $action_being_done these paths:\n\n"; print $printable_list_of_things_to_pondize; print "\n"; } if (@nonexistent_paths) { print "\n\n\nNonexistent file(s) or folder(s) listed in things_to_pondize array!\n\n"; foreach $nonexistent_path (@nonexistent_paths) { $list_of_nonexistent_paths = " $nonexistent_path\n"; # print " $this_full_path\n"; } if ($should_halt_script_if_any_things_to_pondize_dont_exist == true) { print "Couldn't $action_being_done because nonexistent items were found!\n\n$list_of_nonexistent_paths\n\n"; End_Script_and_Wait_for_Return(); } else { print "Warning: incomplete $action_being_done because nonexistent items were found!\n\n$list_of_nonexistent_paths\n\n"; } } if ($count_of_existent_paths<1) { print "\n\nNothing to $action_being_done, aborting.\n\n"; End_Script_and_Wait_for_Return(); } if ($should_ask_if_should_add_file_or_folder_names_to_pondize_destination_name) { print "\n\nPress Return to add file or folder names to the "; if ($action_being_done eq "zip") { print "zip file"; } else { print "pond folder"; } print " name, or type 'n' (without quotes) to not add them. (Or type 'q' to quit.)\n\n> "; $command = ; chomp($command); if ($command eq 'n') { $should_add_file_or_folder_names_to_pondize_destination_name=false; } elsif ($command eq 'q') { End_Script_and_Wait_for_Return(); } else { $should_add_file_or_folder_names_to_pondize_destination_name=true; } } if ($should_ask_for_a_pondize_destination_name_prefix) { print "\n\nPlease type a prefix for the "; if ($action_being_done eq "zip") { print "zip file"; } else { print "pond folder"; } print " which is about to be created.\n\n> "; $prefix_for_pondize_destination_name = ; chomp $prefix_for_pondize_destination_name; } $prefix_for_pondize_destination_name=Convert_Badchars_to_Dashes($prefix_for_pondize_destination_name); print "\n\nPrefix for pondize destination name: $prefix_for_pondize_destination_name \n\n"; if ($should_ask_for_a_pondize_destination_name_suffix) { print "\n\nPlease type a suffix for the "; if ($action_being_done eq "zip") { print "zip file"; } else { print "pond folder"; } print " which is about to be created.\n\n> "; $suffix_for_pondize_destination_name = ; chomp $suffix_for_pondize_destination_name; } sub Convert_Badchars_to_Dashes { $string=$_[0]; $result=$string; $result=~s/[^A-Za-z0-9., _-]/-/g; return $result; } $suffix_for_pondize_destination_name=Convert_Badchars_to_Dashes($suffix_for_pondize_destination_name); print "\n\nSuffix for pondize destination name: $suffix_for_pondize_destination_name \n\n "; Create_Dest_Path_If_Necessary("current_parentdirs_of_pondized_stuff"); sub Create_Dest_Path_If_Necessary { $var=$_[0]; if (!-e $$var) { print "\n\nPath doesn't exist yet - $$var !\nNow attempting to create path\n\n $$var"; $succeeded = mkpath $$var; if ($succeeded) { print "\n\nPath created!"; } else { print "\n\nCouldn't create path $$var !"; } } } CheckForDestPathErrors("current_parentdirs_of_pondized_stuff"); sub CheckForDestPathErrors { $var=$_[0]; if (!-d $$var) { print "\n\nError: "; print $$var; print " is not a directory!\n\n"; print "Sorry, the path provided in the $var variable doesn't lead to a directory. Please put a different path in $var, or make $$var into a directory, and run this script again."; End_Script_and_Wait_for_Return(); } } $current_parentdirs_of_pondized_stuff=AddSlashIfNeeded($current_parentdirs_of_pondized_stuff); sub AddSlashIfNeeded { $this_string=$_[0]; $lastchar = substr($this_string,length($this_string)-1,1); if ($lastchar ne "/") { $this_string .= "/"; } return $this_string; } sub Make_Pondize_Destination_Name { $date = Make_Pondize_Destination_Date(); $result=""; if ($should_add_file_or_folder_names_to_pondize_destination_name ) { if ( $list_of_filesorfols_for_pondize_destination_name ) { $nameparts_without_filesorfols = ""; if ($action_being_done eq "zip") { $nameparts_without_filesorfols = ".zip"; } if ( $prefix_for_pondize_destination_name ) { $nameparts_without_filesorfols = $prefix_for_pondize_destination_name . " - "; } if ( $suffix_for_pondize_destination_name ) { $nameparts_without_filesorfols = $nameparts_without_filesorfols . " - " . $suffix_for_pondize_destination_name; } $nameparts_without_filesorfols = $nameparts_without_filesorfols . " - " . $date; #print "nameparts_without_filesorfols: $nameparts_without_filesorfols"; $length_of_nameparts_without_filesorfols = length ($nameparts_without_filesorfols); $shortened_max=$max_length_of_pondize_destination_name - $length_of_nameparts_without_filesorfols; #print "length_of_nameparts_without_filesorfols: $length_of_nameparts_without_filesorfols "; $length_of_filesorfols_list = length ($list_of_filesorfols_for_pondize_destination_name); if ( $length_of_filesorfols_list > $shortened_max ) { $list_of_filesorfols_for_pondize_destination_name = substr($list_of_filesorfols_for_pondize_destination_name, 0, $shortened_max); } } } if ( $prefix_for_pondize_destination_name ) { $result = $prefix_for_pondize_destination_name . " - "; } if ($should_add_file_or_folder_names_to_pondize_destination_name ) { if ( $list_of_filesorfols_for_pondize_destination_name ) { $result = $result . $list_of_filesorfols_for_pondize_destination_name . " - "; } } $result = $result . $date; if ($suffix_for_pondize_destination_name) { $result = $result . " - " . $suffix_for_pondize_destination_name; } if ($should_convert_badchars_in_pondize_destination_name) { $result=Convert_Badchars_to_Dashes($result); } return $result; } sub Make_Pondize_Destination_Date { ($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime(time); $year = 1900 + $yearOffset; $month = $month + 1; $second = sprintf("%02d", $second); $minute = sprintf("%02d", $minute); $hour = sprintf("%02d", $hour); $result = $year . "_" . $month . "_" . $dayOfMonth . " " . $hour . "," . $minute . "," . $second; if ($should_put_am_or_pm_in_time) { if ($hour>=12) { $result = $result . " pm"; } else { $result = $result . " am"; } } return $result; } print "\n\n\n"; if ($should_use_full_paths == true) { print "Using full paths for files being pondized."; } else { print "Using short paths for files being pondized."; } print "\n"; $pondize_destination_name=Make_Pondize_Destination_Name(); print "\n\nPondize destination name: $pondize_destination_name\n\n"; if ($action_being_done eq "zip") { $current_pondize_destination_path=$current_parentdirs_of_pondized_stuff . $pondize_destination_name . ".zip"; } else { $current_pondize_destination_path=$current_parentdirs_of_pondized_stuff . $pondize_destination_name; Create_Dest_Path_If_Necessary("current_pondize_destination_path"); } print "\n\nGoing to try to $action_being_done these paths:\n\n"; print $printable_list_of_things_to_pondize; print "\n"; print "\n\nTrying to make "; if ($action_being_done eq "zip") { print "zip"; } else { print "pondized folder"; } print "...\n\n\n"; sub Make_Unique_Destpath { # 13:58 02/08/2014. This subroutine isn't very well-tested. $dest_path=$_[0]; $path=$_[1]; $file_or_folder=$_[2]; $tries=1; $noext_fileorfol_name=""; $parsed_path=""; $ext=""; if ($should_use_full_paths == false) { ($noext_fileorfol_name,$parsed_path,$ext) = fileparse($file_or_folder); } else { $full_path=$path . "/" . $file_or_folder; ($noext_fileorfol_name,$parsed_path,$ext) = fileparse($full_path); } while ($tries<100 && -e $dest_path ) { $new_bits = "--copy-$tries"; $length_of_new_bits=length ($new_bits); $file_or_folder_name_plus_new_bits = $file_or_folder . $new_bits; $length_of_noext_fileorfol_name_plus_new_bits = length ($noext_fileorfol_name_plus_new_bits); if ( $length_of_noext_fileorfol_name_plus_new_bits>200 ) { $shortened_fileorfol_name=substr($noext_fileorfol_name, 0, 200); if ($should_use_full_paths == false) { $dest_path = $current_pondize_destination_path . "/$shortened_fileorfol_name" . $new_bits; } else { $dest_path = $current_pondize_destination_path . "/$path/$shortened_fileorfol_name" . $new_bits; } } else { if ($should_use_full_paths == false) { $dest_path = $current_pondize_destination_path . "/$noext_fileorfol_name" . $new_bits; } else { $dest_path = $current_pondize_destination_path . "/$path/$noext_fileorfol_name" . $new_bits; } } if ( $ext ) { $dest_path = $dest_path . "." . $ext; } } return $dest_path; } sub Escape_Quotes { $string=$_[0]; $result=$string; $result=~s/"/\\"/g; return $result; } foreach $fullpath (keys %parentdirs_and_file_or_folder_name) { $array_reference = $parentdirs_and_file_or_folder_name{$fullpath}; @the_array=@$array_reference; $path=$the_array[0]; $file_or_folder=$the_array[1]; if ($action_being_done eq "zip") { chdir $path; $current_pondize_destination_path_with_escaped_quotes=Escape_Quotes($current_pondize_destination_path); if ($should_use_full_paths == false) { $file_or_folder_with_escaped_quotes=Escape_Quotes($file_or_folder); $shell_command_line="zip -r \"$current_pondize_destination_path\" \"$file_or_folder_with_escaped_quotes\""; } else { chdir "/"; $longfilepath=$path . $file_or_folder; $longfilepath_with_escaped_quotes=Escape_Quotes($longfilepath); $shell_command_line="zip -r \"$current_pondize_destination_path\" \"$longfilepath_with_escaped_quotes\""; } print "# $shell_command_line\n\n"; system ($shell_command_line); } else # Pondizing, not zipping { if ($should_use_full_paths == false) { #chdir $path; #print "\n\n\n\nIN HERE\n\n\n"; $dest_path = $current_pondize_destination_path . "/$file_or_folder"; if (-e $dest_path) { $dest_path = Make_Unique_Destpath($dest_path, $path, $file_or_folder); } } elsif ($should_use_full_paths == true) { $full_path_inside_pondize_destination_path = $current_pondize_destination_path . "/" . $path; mkpath ($full_path_inside_pondize_destination_path); $dest_path = $full_path_inside_pondize_destination_path . "/$file_or_folder"; if (-e $dest_path) { $dest_path = Make_Unique_Destpath($dest_path, $path, $file_or_folder); } } $copy_succeeded=false; $copyfrompath = $path . $file_or_folder; print " copyfrompath: $copyfrompath dest_path: $dest_path "; if (!-e $dest_path) { # 10:14 02/08/2014. Originally, I wanted to just use the Perl # commands copy and dircopy, but then I found they don't preserve # timestamps. And maybe not even permissions (didn't check). # # So, had to use the shell command cp to copy files instead. # $copyfrompath_with_escaped_quotes=Escape_Quotes($copyfrompath); # $dest_path_with_escaped_quotes=Escape_Quotes($dest_path); if (-f $copyfrompath) # If it's a file... { @system_args = ("cp", "--preserve", $copyfrompath, $dest_path); #$shell_command_line = "cp --preserve $copyfrompath $dest_path"; #$copy_succeeded = copy ( $copyfrompath, $dest_path); } elsif (-d $copyfrompath) # If it's a directory... { #$copy_succeeded = dircopy ( $copyfrompath, $dest_path); @system_args = ("cp", "--preserve", "--recursive", $copyfrompath, $dest_path); #$shell_command_line = "cp --preserve --recursive $copyfrompath $dest_path"; } print "\n\n# (not the exact command line used:) @system_args\n\n"; #print "\n\n# $shell_command_line\n\n"; # system ($shell_command_line); system(@system_args); } #if ( !$copy_succeeded) #{ print "FAILED to copy $copyfrompath to $dest_path! "; #} } } print "\n\n\nHopefully backed up all these paths:\n\n"; print $printable_list_of_things_to_pondize; print "\n"; if ($should_pondize_to_temp_location_then_copy_to_actual_pond) { $final_pondize_destination_path = $full_path_to_pond . $pondize_destination_name; $copyfrompath = $current_pondize_destination_path; #$copyfrompath_with_escaped_quotes=Escape_Quotes($copyfrompath); if ($action_being_done eq "zip") { $final_pondize_destination_path = $final_pondize_destination_path . ".zip"; } #$final_pondize_destination_path_with_escaped_quotes=Escape_Quotes($final_pondize_destination_path); Create_Dest_Path_If_Necessary("full_path_to_pond"); if (!-e $final_pondize_destination_path) { @system_args = ("cp", "--preserve", "--recursive", $copyfrompath, $final_pondize_destination_path); #print @system_args; system(@system_args); } } $current_pondize_destination_path_to_display=$current_pondize_destination_path; print "\n\nFinished $action_being_done!\n"; print "\nResults at: $current_pondize_destination_path_to_display\n"; if (-e $current_pondize_destination_path) { #chmod 0400, $current_pondize_destination_path; # Owner:Read permissions only. $full_path_to_pond_with_escaped_quotes=Escape_Quotes($full_path_to_pond); if ($open_pond_folder_when_script_is_finished == true ) { $command_line="$file_manager_shell_command_to_use \"$full_path_to_pond_with_escaped_quotes\""; print "\n\n\nOpening pond folder, $full_path_to_pond...\n # $command_line\n\n"; system ($command_line); } } else # Couldn't find the zip file at the path where it's now supposed to be. { print "The end of the script was reached, but no zip file was found where it was supposed to be!\n\nTried to create $current_pondize_destination_path but failed."; } if (@nonexistent_paths) { print "\n\n\nNonexistent file(s) or folder(s) listed in things_to_pondize array!"; print "\n\nWarning: incomplete $action_being_done because nonexistent items were found!\n\n$list_of_nonexistent_paths\n\n"; } if ($should_autoclose_at_end_of_script ) { End_Script_with_Autoclose(); } else { End_Script_and_Wait_for_Return(); } sub End_Script_with_Autoclose { print "\n\nScript finished!\n"; print "\n\nThis window will automatically close in $num_of_seconds_before_autoclose seconds.\n\n\n"; sleep $num_of_seconds_before_autoclose; die; } sub End_Script_and_Wait_for_Return() { print "\n\nScript finished!\n"; print "\nYou can press Return (or Enter) to close this window.\n"; $wait_for_return = ; die; }