? ImportToDD.diff
? Updater.cs.Backup1
? bin
Index: FileImportBackend.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/FileImportBackend.cs,v
retrieving revision 1.28
diff -u -r1.28 FileImportBackend.cs
--- FileImportBackend.cs	3 Dec 2005 18:43:55 -0000	1.28
+++ FileImportBackend.cs	15 Feb 2006 23:30:07 -0000
@@ -115,8 +115,8 @@
 						 FSpot.Global.PhotoDirectory,
 						 System.IO.Path.DirectorySeparatorChar,
 						 time.Year,
-						 time.Month,
-						 time.Day);
+						 time.ToString("MM"),	// To get months with leading 0 as in 01 - 12 
+						 time.ToString("dd"));	// To get days with leading 0 as in 01 - 31 
 		
 		if (!System.IO.Directory.Exists (dest_dir))
 			System.IO.Directory.CreateDirectory (dest_dir);
Index: Updater.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/Updater.cs,v
retrieving revision 1.4
diff -u -r1.4 Updater.cs
--- Updater.cs	13 Feb 2006 07:27:36 -0000	1.4
+++ Updater.cs	15 Feb 2006 23:30:08 -0000
@@ -62,6 +62,341 @@
 				System.Console.WriteLine ("Other tag restored.  Sorry about that!");
 			});
 			
+			// Modify directory structure so Day and Months have a leading 0's if needed. 01 instead of 1
+			AddUpdate (delegate (SqliteConnection connection) {
+				string slask, orig_directory, new_directory, orig_name, orig_name_w_extension, old_photo, new_photo, photo_extension;
+				int i;
+				// We keep 4 ArrayList to keep track of Directory, photo and id. They are syncronised, so 
+				// there will be duplicates in Directory and ID if the photo has versions.
+				ArrayList new_directories = new ArrayList(); // A list of all directories to be created
+				ArrayList old_photo_names = new ArrayList(); // A list of all photos to be moved
+				ArrayList new_photo_names = new ArrayList(); // A list of the new photo name
+				ArrayList photo_ids = new ArrayList(); // A list of the internal photo id of the photos to be moved
+				
+				orig_name = "";
+				photo_extension = "";
+
+				Console.WriteLine ("About to update the directory structure (adding leading 0's).");
+				
+				// Get minimum Photo ID
+				slask = SelectSingleString (
+					String.Format ("SELECT MIN (id) from photos"));
+
+				if (slask == null)
+					return;
+
+				int min_photo_id = System.Int32.Parse (slask);
+				
+				// Get maximum Photo ID
+				slask = SelectSingleString (
+					String.Format ("SELECT MAX (id) from photos"));
+
+				int max_photo_id = System.Int32.Parse (slask);
+
+//				Console.WriteLine ("Min photo id = {0}, Max photo id = {1}", min_photo_id, max_photo_id);
+				
+				// Iterate through all photos to check if directory structure needs to be modified
+				for (int id = min_photo_id;  id <= max_photo_id; id++) {
+
+					//Console.WriteLine ("Checking photo {0}", id);
+					
+					// Check if starting with FSpot.Global.PhotoDirectory (~/Photos)
+					orig_directory = SelectSingleString (
+						String.Format ("SELECT directory_path from photos where id = {0}", id));
+	
+					// Set new_directory to same as old_directory by default
+					new_directory = orig_directory;
+
+					if (orig_directory.StartsWith (FSpot.Global.PhotoDirectory)) {
+						// Console.WriteLine ("{0} ({1}) is under ~/Photos.", id, orig_directory);
+
+						// Check if Day and/or Month is less than 10
+						slask = SelectSingleString (
+							String.Format ("SELECT time from photos where id = {0}", id));
+						
+						// Convert the sqlite string to a long, and then to unix time.
+						DateTime photo_time = DbUtils.DateTimeFromUnixTime ( System.Int64.Parse (slask) );
+						
+						if ((photo_time.Month < 10) || (photo_time.Day < 10)) {
+							// Get the name of the photo
+							orig_name_w_extension = SelectSingleString (
+								String.Format ("SELECT name from photos where id = {0}", id));
+							photo_extension = System.IO.Path.GetExtension (orig_name_w_extension);
+							orig_name = System.IO.Path.GetFileNameWithoutExtension (orig_name_w_extension);
+							
+							// Console.WriteLine ("Need to modify photo id {0} - directory {1} - Month {2} - Day {3}, Name {4}", id, orig_directory, photo_time.Month, photo_time.Day, orig_name );
+
+							// Ok, lets create the directory path
+							new_directory = String.Format ("{0}{1}{2}{1}{3}{1}{4}",
+								FSpot.Global.PhotoDirectory,
+								System.IO.Path.DirectorySeparatorChar,
+								photo_time.Year,
+								photo_time.ToString("MM"),	// To get months with leading 0 as in 01 - 12 
+								photo_time.ToString("dd"));	// To get days with leading 0 as in 01 - 31 								
+
+							// Console.WriteLine ("New directory path {0} - {1}", new_directory, new_directory.Replace("'", "''"));
+
+						} // if Month or day < 10
+
+						// Only proceed if month/day directory name is missing leading "0"
+						if (orig_directory != new_directory) {
+
+							// Lets create the old and the new photo names
+							old_photo = String.Format ("{0}{1}{2}{3}", 
+								orig_directory, System.IO.Path.DirectorySeparatorChar, orig_name, photo_extension);
+							new_photo = String.Format ("{0}{1}{2}{3}", 
+								new_directory, System.IO.Path.DirectorySeparatorChar, orig_name, photo_extension);
+							
+							// Ensure that the old photo name exists, and that the new photo name do not exist
+							if (!System.IO.File.Exists (old_photo))
+								throw new Exception (String.Format("Photo with name {0} do not exists", old_photo));
+							if (System.IO.File.Exists (new_photo))
+								throw new Exception (String.Format("Photo with name {0} already exists", new_photo));
+							
+//							Console.WriteLine ("Rename '{0}' to '{1}'", old_photo, new_photo);
+
+							// Store all names for processing last
+							old_photo_names.Add (old_photo);
+							new_photo_names.Add (new_photo);
+							new_directories.Add (new_directory);
+							photo_ids.Add (id);
+							
+							// We have done the main version, now we need to move all versions as well
+							int min_version_id = 9999;
+							int max_version_id = 0;
+							
+							// Get minimum Version ID
+							slask = SelectSingleString (
+								String.Format ("SELECT MIN (version_id) from photo_versions where photo_id = {0}", id));
+
+							if (slask == null)
+								min_version_id = 9999;	// no versions exists, set min to be more than max.
+							else {
+								min_version_id = System.Int32.Parse (slask);
+				
+								// Get maximum Photo ID
+								slask = SelectSingleString (
+									String.Format ("SELECT MAX (version_id) from photo_versions where photo_id = {0}", id));
+
+								if (slask == null)
+									max_version_id = 0; // no versions exists, set max to be less than min.
+								else
+									max_version_id = System.Int32.Parse (slask);
+							} // if min(verson_id) exists
+							
+							// Console.WriteLine ("Min version id = {0}, Max version id = {1}", min_version_id, max_version_id);
+							for (int vid = min_version_id;  vid <= max_version_id; vid++) {
+								string version_name = SelectSingleString (
+									String.Format ("SELECT name from photo_versions where photo_id = {0} and version_id = {1}", id, vid));
+								
+								// Lets create the old and the new photo names
+								old_photo = String.Format ("{0}{1}{2} ({3}){4}", 
+									orig_directory, System.IO.Path.DirectorySeparatorChar, orig_name, version_name, photo_extension);
+								new_photo = String.Format ("{0}{1}{2} ({3}){4}", 
+									new_directory, System.IO.Path.DirectorySeparatorChar, orig_name, version_name, photo_extension);
+
+								// Ensure that the old photo name exists, and that the new photo name do not exist
+								if (!System.IO.File.Exists (old_photo))
+									throw new Exception (String.Format("Photo with name {0} do not exists", old_photo));
+								if (System.IO.File.Exists (new_photo))
+									throw new Exception (String.Format("Photo with name {0} already exists", new_photo));
+
+								// Store all names for processing last
+								old_photo_names.Add (old_photo);
+								new_photo_names.Add (new_photo);
+								new_directories.Add (new_directory);	// just so all array lists are the same
+								photo_ids.Add (id);			// just so all array lists are the same
+
+//								Console.WriteLine ("Rename {0} to {1}", old_photo, new_photo);
+
+								// Console.WriteLine ("Photo id {0}, Directory {1}, Version {2}, Name {3}", id, orig_directory, vid, name);
+							} // for each version
+							
+							
+						} // if month and day part missing leading "0"
+//						else  // Month and Day > 10, or have leading "0"
+//							Console.WriteLine ("----> {0} ----< directory {1} - Month {2} - Day {3} is OK.", id, orig_directory, photo_time.Day, photo_time.Month);
+						
+					} // under ~/Photos
+//					else  // Not under ~/Photos
+//						Console.WriteLine ("----> {0} ----< Directory ({1}) is outside ~/Photos ignore it.", id, orig_directory);
+
+				} // end for
+			
+				// Lets ensure that our ArrayLists have the same amount of entries.
+				if ((new_directories.Count == old_photo_names.Count) &&
+					(old_photo_names.Count == new_photo_names.Count) &&
+					(new_photo_names.Count == photo_ids.Count)) {
+//					Console.WriteLine (String.Format("ArrayList have same number of entries: dirs {0}, old {1}, new {2}, id {3}", new_directories.Count, old_photo_names.Count, new_photo_names.Count, photo_ids.Count));
+				} else {
+					throw new Exception (String.Format(
+					"ArrayList have different number of entries: dirs {0}, old {1}, new {2}, id {3}",
+					new_directories.Count, old_photo_names.Count, new_photo_names.Count, photo_ids.Count));
+				}
+
+				// Start processing, if we have some photo to move
+				if (new_directories.Count > 0) {
+					
+					// Ok we now have all the data. Lets process it.
+					// We do all the work inside an internal try/catch so we can roll back everyting if needed.
+
+					try {
+						Console.WriteLine ("Creating new directories");
+	
+						// Ensure that the new directory exists 
+						for (i = 0; i < new_photo_names.Count; i++) {
+							if ( !System.IO.Directory.Exists(new_directories[i].ToString()) ) {
+								// FIXME Directory Permissions?
+								System.IO.Directory.CreateDirectory(new_directories[i].ToString());
+//								Console.WriteLine ("Created {0} - {1}", i, new_directories[i].ToString());
+							}
+						} // for 
+
+						Console.WriteLine ("Creating hard links for the new photos");
+
+						// Create a hard link instead of copy. Save spaces and goes fast
+						// FIXME Does this work for BSD????
+						for (i = 0; i < new_photo_names.Count; i++) {
+							Mono.Unix.Native.Syscall.link (
+								old_photo_names[i].ToString(), new_photo_names[i].ToString());
+//							Console.WriteLine ("Linked {0} - {1} to {2}", i, old_photo_names[i].ToString(), new_photo_names[i].ToString());
+						} // for 
+
+						Console.WriteLine ("Updating the directory path in the database");
+
+						// Modify main photo
+						for (i = 0; i < new_directories.Count; i++) {
+							ExecuteNonQuery ( 
+								String.Format ("UPDATE photos set directory_path = '{0}' WHERE id = {1}", 
+									new_directories[i].ToString().Replace ("'", "''"), photo_ids[i]));
+//							Console.WriteLine ("Updated database {0} - id {1} {2}", i, photo_ids[i], new_directories[i].ToString());
+						} // for 
+
+						Console.WriteLine ("Updating the thumbnails");
+
+						// Move the thumbnail
+						for (i = 0; i < new_photo_names.Count; i++) {
+							if (System.IO.File.Exists (Gnome.Thumbnail.PathForUri (old_photo_names[i].ToString(), Gnome.ThumbnailSize.Large))) {
+								System.IO.File.Move (
+									Gnome.Thumbnail.PathForUri (old_photo_names[i].ToString(), Gnome.ThumbnailSize.Large),
+									Gnome.Thumbnail.PathForUri (new_photo_names[i].ToString(), Gnome.ThumbnailSize.Large));
+//								Console.WriteLine ("Updated ThumbNails {0} - {1}", i, new_photo_names[i].ToString());
+							} // if old thumbnail exists
+						} // for 
+						
+// Lets quit since we are only testing...
+// throw new Exception ("Testing only, so revert changes.");
+					
+					} catch (System.Exception e) {
+						Console.WriteLine ("Some error occurred, so we are rolling back");
+//Console.WriteLine ("Press enter.....");
+//string slask2 = Console.ReadLine();
+						
+						// Lets do everything in reverse order
+						
+						Console.WriteLine ("Rolling back the thumbnails");
+
+						// Move the thumbnail (only if the new one exists)
+						for (i = 0; i < new_photo_names.Count; i++) {
+							if (System.IO.File.Exists(Gnome.Thumbnail.PathForUri (new_photo_names[i].ToString(), Gnome.ThumbnailSize.Large))) {
+								System.IO.File.Move (
+									Gnome.Thumbnail.PathForUri (new_photo_names[i].ToString(), Gnome.ThumbnailSize.Large),
+									Gnome.Thumbnail.PathForUri (old_photo_names[i].ToString(), Gnome.ThumbnailSize.Large));
+//								Console.WriteLine ("Rolledback ThumbNails {0} - {1}", i, old_photo_names[i].ToString());
+							}
+						} // for 
+
+						// Database rolling back will be handle by transaction rollback.
+	
+						Console.WriteLine ("Removing just created new photos");
+						// Delete the new photo
+						for (i = 0; i < new_photo_names.Count; i++) {
+							if (System.IO.File.Exists(new_photo_names[i].ToString()))
+								try {
+									System.IO.File.Delete ( new_photo_names[i].ToString());
+//									Console.WriteLine ("Remove Linked {0} - {1}", i, new_photo_names[i].ToString());
+								} catch  { // if some error (not empty?), lets continue
+								}
+						} // for 
+
+						Console.WriteLine ("Delete the new directory");
+						for (i = 0; i < new_photo_names.Count; i++) {
+							if (System.IO.Directory.Exists(new_directories[i].ToString()))
+								try {
+									System.IO.Directory.Delete (new_directories[i].ToString());
+//									Console.WriteLine ("Deleted directory {0} - {1}", i, new_directories[i].ToString());
+								} catch  { // if some error (not empty?), lets continue
+								}
+						} // for 
+
+						// Rethrow the exception so we rollback the database.
+						throw e;
+					
+					} // catch
+			
+					// Ok, we got to this point, which means all is ok. Only one thing left, to clean up.
+					// Delete the old photos
+					Console.WriteLine ("Removing the old photos");
+					for (i = 0; i < old_photo_names.Count; i++) {
+						try {
+							System.IO.File.Delete ( old_photo_names[i].ToString());
+//							Console.WriteLine (String.Format("Removed old file {0}", old_photo_names[i].ToString()));
+						} catch  {
+							Console.WriteLine (String.Format("Could not delete {0}, continuing", old_photo_names[i].ToString()));
+						}
+					} // for 
+				
+					// Delete the old directories (Month and Day)
+					Console.WriteLine ("Removing the old Month / Day directory");
+
+					ArrayList dir_list = new ArrayList();
+					string dir_str;
+
+					for (i = 0; i < old_photo_names.Count; i++) 
+						dir_list.Add (System.IO.Path.GetDirectoryName (old_photo_names[i].ToString()));
+					dir_list.Sort();
+					int last_i = -1;
+					for (i = 0; i < dir_list.Count; i++) 
+						if ((last_i < 0) || (dir_list[i].ToString() != dir_list[last_i].ToString()))  {
+							dir_str = dir_list[i].ToString();
+							if (System.IO.Directory.Exists(dir_str)) 
+								try {
+									System.IO.Directory.Delete(dir_str);
+//									Console.WriteLine (String.Format("Removed old directory {0}", dir_str));
+								} catch  {
+									Console.WriteLine (String.Format("Could not delete {0} (not empty?), continuing", dir_str));
+								}
+							last_i = i;
+						}
+					// Lets remove the months
+					// First remove the day part of the directory string
+					for (i = 0; i < dir_list.Count; i++) {
+						dir_str = dir_list[i].ToString();
+						while (!dir_str.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())) {
+							dir_str = dir_str.Remove(dir_str.Length-1, 1); // remove last char
+						} // while
+						dir_list[i] = dir_str.Remove(dir_str.Length-1, 1); // remove last "/"
+
+					} // for
+					dir_list.Sort();
+					last_i = -1;
+					for (i = 0; i < dir_list.Count; i++) 
+						if ((last_i < 0) || (dir_list[i].ToString() != dir_list[last_i].ToString()))  {
+							dir_str = dir_list[i].ToString();
+							bool single_digit_month = (dir_str.Substring (dir_str.Length - 2, 1) == System.IO.Path.DirectorySeparatorChar.ToString());
+							if (single_digit_month && System.IO.Directory.Exists(dir_str)) 
+								try {
+									System.IO.Directory.Delete(dir_str);
+//									Console.WriteLine (String.Format("Removed old directory {0}", dir_str));
+								} catch  {
+									Console.WriteLine (String.Format("Could not delete {0} (not empty?), continuing", dir_str));
+								}
+							last_i = i;
+						} // if
+				} // If new_directories > 0
+				
+			}); // AddUpdate
+
 			// Update from version 2 to 3
 			//AddUpdate (delegate (SqliteConnection connection) {
 			//	do update here
