[banshee] [solitary] big update to solitary, mostly complete



commit ddd121618c9131ae9ea67a70ef962190d436b3ae
Author: Aaron Bockover <abockover novell com>
Date:   Mon Jan 11 13:21:46 2010 -0500

    [solitary] big update to solitary, mostly complete
    
    Supports rebuilding symlinks now, the missing piece in making
    the bundle work. Lots of other various changes I've made.

 build/bundle/solitary/AssemblyItem.cs      |   18 +++++--
 build/bundle/solitary/Entry.cs             |    3 +-
 build/bundle/solitary/Item.cs              |   52 ++++++++++++++++++--
 build/bundle/solitary/Makefile             |    2 +
 build/bundle/solitary/NativeLibraryItem.cs |   72 +++++++++++++++++++++++++--
 build/bundle/solitary/PathExtensions.cs    |   53 ++++++++++++++++++++
 build/bundle/solitary/ProcessTools.cs      |    4 ++
 build/bundle/solitary/Solitary.cs          |   34 ++++++++-----
 build/bundle/solitary/SymlinkItem.cs       |   68 ++++++++++++++++++++++++++
 9 files changed, 277 insertions(+), 29 deletions(-)
---
diff --git a/build/bundle/solitary/AssemblyItem.cs b/build/bundle/solitary/AssemblyItem.cs
index 373a61d..45465cc 100644
--- a/build/bundle/solitary/AssemblyItem.cs
+++ b/build/bundle/solitary/AssemblyItem.cs
@@ -48,6 +48,16 @@ public class AssemblyItem : Item
         }
 
         yield return this;
+        
+        var sibling = Item.Resolve (Confinement, File.FullName + ".mdb");
+        if (sibling != null) {
+            yield return sibling;
+        } 
+
+        sibling = Item.Resolve (Confinement, File.FullName + ".config");
+        if (sibling != null) {
+            yield return sibling;
+        }
 
         foreach (var item in ReadAssembly ()) {
             yield return item;
@@ -90,10 +100,10 @@ public class AssemblyItem : Item
         foreach (var module in pinvoke_modules) {
             var lib = LocateNativeLibrary (Assembly.Location, module);
             if (lib != null) {
-                var item = new NativeLibraryItem () {
-                    Confinement = Confinement,
-                    File = new FileInfo (lib)
-                };
+                var item = Item.Resolve (Confinement, new FileInfo (lib));
+                if (item == null) {
+                    continue;
+                }
                 foreach (var child_item in item.Load ()) {
                     yield return child_item;
                 }
diff --git a/build/bundle/solitary/Entry.cs b/build/bundle/solitary/Entry.cs
index d4b8032..2c2a6ea 100644
--- a/build/bundle/solitary/Entry.cs
+++ b/build/bundle/solitary/Entry.cs
@@ -74,8 +74,9 @@ public static class Entry
                 foreach (var collect_item in item.Load ()) {
                     solitary.Items.Add (collect_item);
                     total_size += collect_item.File.Length;
-                    Console.WriteLine (" + {0} ({1} KB)",
+                    Console.WriteLine (" + {0} ({1} - {2} KB)",
                         collect_item.File.Name,
+                        collect_item.GetType ().Name,
                         collect_item.File.Length / 1024);
                 }
             }
diff --git a/build/bundle/solitary/Item.cs b/build/bundle/solitary/Item.cs
index bc821a8..66469c9 100644
--- a/build/bundle/solitary/Item.cs
+++ b/build/bundle/solitary/Item.cs
@@ -42,6 +42,8 @@ public abstract class Item
     public Solitary Confinement { get; set; }
     public abstract IEnumerable<Item> Load ();
 
+    public FileInfo OriginalFile { get; private set; }
+
     private FileInfo file;
     public FileInfo File {
         get { return file; }
@@ -52,26 +54,58 @@ public abstract class Item
             }
 
             file = value;
-            var link = new UnixSymbolicLinkInfo (file.FullName);
-            if (link.HasContents) {
-                file = new FileInfo (link.GetContents ().FullName);
+            if (OriginalFile == null) {
+                OriginalFile = file;
             }
         }
     }
 
     public bool IsValidConfinementItem (Item item)
     {
+        return IsValidConfinementItem (item, true);
+    }
+    
+    public bool IsValidConfinementItem (Item item, bool checkExists)
+    {
         if (Confinement.ConfinementRoot != null &&
             !item.File.FullName.StartsWith (Confinement.ConfinementRoot)) {
             return false;
+        } else if (!checkExists) {
+            return true;
         }
 
         return !Confinement.Items.Exists (c => c.File.FullName == item.File.FullName);
     }
 
+    public string GetRelocationPath ()
+    {
+        return GetRelocationPath (File.FullName);
+    }
+
+    public string GetRelocationPath (string path)
+    {
+        if (Confinement.ConfinementRoot != null) {
+            path = path.Substring (Confinement.ConfinementRoot.Length + 1);
+        }
+        return Path.Combine (Confinement.OutputPath, path);
+    }
+
+    public virtual void Relocate ()
+    {
+        var path = GetRelocationPath ();
+        Directory.CreateDirectory (Path.GetDirectoryName (path));
+        System.IO.File.Copy (File.FullName, path);
+        File = new FileInfo (path);
+    }
+
+    public static Item Resolve (Solitary confinement, string path)
+    {
+        return Resolve (confinement, new FileInfo (path));
+    }
+
     public static Item Resolve (Solitary confinement, FileInfo file)
     {
-        if (file.Name.StartsWith (".")) {
+        if (!file.Exists || file.Name.StartsWith (".")) {
             return null;
         }
 
@@ -82,6 +116,13 @@ public abstract class Item
                 return null;
             }
         }
+       
+        if (SymlinkItem.IsSymlink (file.FullName)) { 
+            return new SymlinkItem () {
+                File = file,
+                Confinement = confinement
+            };
+        }
 
         switch (GetFileType (file)) {
             case FileType.PE32Executable: 
@@ -108,6 +149,9 @@ public abstract class Item
         }
         
         var line = proc.StandardOutput.ReadLine ();
+        
+        proc.Dispose ();
+        
         if (line == null) {
             return FileType.Data;
         }
diff --git a/build/bundle/solitary/Makefile b/build/bundle/solitary/Makefile
index 8d790a8..10d0f67 100644
--- a/build/bundle/solitary/Makefile
+++ b/build/bundle/solitary/Makefile
@@ -5,7 +5,9 @@ SOURCE = \
 	AssemblyItem.cs \
 	NativeLibraryItem.cs \
 	DataItem.cs \
+	SymlinkItem.cs \
 	ProcessTools.cs \
+	PathExtensions.cs \
 	Entry.cs \
 	Options.cs
 
diff --git a/build/bundle/solitary/NativeLibraryItem.cs b/build/bundle/solitary/NativeLibraryItem.cs
index 45c2bdf..513dbf9 100644
--- a/build/bundle/solitary/NativeLibraryItem.cs
+++ b/build/bundle/solitary/NativeLibraryItem.cs
@@ -42,16 +42,76 @@ public class NativeLibraryItem : Item
         }
 
         yield return this;
-
+        
         foreach (var dep in deps) {
-            var item = new NativeLibraryItem () {
-                File = new FileInfo (dep),
-                Confinement = Confinement
-            };
-
+            var item = Item.Resolve (Confinement, new FileInfo (dep));
+            if (item == null) {
+                continue;
+            }
+            
             foreach (var child_item in item.Load ()) {
                 yield return child_item;
             }
         }
     }
+
+    public void Strip ()
+    {
+        var proc = ProcessTools.CreateProcess ("strip",
+            String.Format ("-u -r \"{0}\"", File.FullName));
+        if (proc != null) {
+            proc.Dispose ();
+        }
+    }
+
+    public void RelocateDependencies ()
+    {
+        if (ProcessTools.Host != ProcessHost.Darwin) {
+            throw new ApplicationException ("Relocation not supported on anything but Darwin");
+        }
+
+        var proc = ProcessTools.CreateProcess ("otool", "-D " + File.FullName);
+        if (proc == null) {
+            return;
+        }
+        
+        string t, dep_id = null;
+        while ((t = proc.StandardOutput.ReadLine ()) != null) {
+            dep_id = t.Trim ();
+            if (dep_id.StartsWith (Confinement.ConfinementRoot)) {
+                dep_id = dep_id.Substring (Confinement.ConfinementRoot.Length + 1); 
+            }
+
+            dep_id = Path.GetFileName (t.Trim ());
+        }
+            // dep_id = PathExtensions.RelativePath (File.FullName,
+            //    Path.GetDirectoryName (dep_id.Trim ()));
+
+        proc.Dispose ();
+
+        int reloc_count = 0;
+
+        var deps = ProcessTools.GetNativeDependencies (File);
+        foreach (var dep in deps) {
+            if (Confinement.ConfinementRoot != null &&
+                !dep.StartsWith (Confinement.ConfinementRoot)) {
+                continue;
+            }
+            
+            // var rel_dep = PathExtensions.RelativePath (dep,
+            //    Path.GetDirectoryName (OriginalFile.FullName));
+            
+            var rel_dep = dep.Substring (Confinement.ConfinementRoot.Length + 1);
+            rel_dep = Path.GetFileName (rel_dep);
+            proc = ProcessTools.CreateProcess ("install_name_tool", String.Format (
+                "-change \"{0}\" \"{1}\" -id \"{2}\" \"{3}\"",
+                dep, rel_dep, dep_id, File.FullName));
+            if (proc != null) {
+                reloc_count++;
+                proc.Dispose ();
+            }
+        }
+
+        Console.WriteLine (" + {0} ({1} relocs)", File.Name, reloc_count);
+    }
 }
diff --git a/build/bundle/solitary/PathExtensions.cs b/build/bundle/solitary/PathExtensions.cs
new file mode 100644
index 0000000..b8bf71d
--- /dev/null
+++ b/build/bundle/solitary/PathExtensions.cs
@@ -0,0 +1,53 @@
+// 
+// PathExtensions.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2009-2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+public static class PathExtensions
+{
+    public static string RelativePath (string path, string start)
+    {
+        var start_list = Path.GetFullPath (start).Split (Path.DirectorySeparatorChar);
+        var path_list = Path.GetFullPath (path).Split (Path.DirectorySeparatorChar);
+        var shared_count = CommonPrefix (path_list, start_list).Length;
+
+        var rel_list = new List<string> ();
+        for (int i = 0; i < start_list.Length - shared_count; rel_list.Add (".."), i++);
+        for (int i = shared_count; i < path_list.Length; rel_list.Add (path_list[i++]));
+        
+        return String.Join (Path.DirectorySeparatorChar.ToString (), rel_list.ToArray ());
+    }
+
+    public static string [] CommonPrefix (string [] a, string [] b)
+    {
+        var min = Math.Min (a.Length, b.Length);
+        var common = new List<string> (min);
+        for (int i = 0; i < min && a[i] == b[i]; common.Add (a[i++]));
+        return common.ToArray ();
+    }
+}
diff --git a/build/bundle/solitary/ProcessTools.cs b/build/bundle/solitary/ProcessTools.cs
index 52e3429..a7b2e23 100644
--- a/build/bundle/solitary/ProcessTools.cs
+++ b/build/bundle/solitary/ProcessTools.cs
@@ -53,6 +53,8 @@ public static class ProcessTools
             case "darwin": Host = ProcessHost.Darwin; break;
             case "linux": Host = ProcessHost.Linux; break;
         }
+
+        uname.Dispose ();
     }
 
     public static Process CreateProcess (string cmd)
@@ -100,6 +102,8 @@ public static class ProcessTools
             }
         }
 
+        proc.Dispose ();
+
         return items;
     }
 }
diff --git a/build/bundle/solitary/Solitary.cs b/build/bundle/solitary/Solitary.cs
index 258ebcd..eacfd22 100644
--- a/build/bundle/solitary/Solitary.cs
+++ b/build/bundle/solitary/Solitary.cs
@@ -141,27 +141,33 @@ public class Solitary
 
     public void CreateBundle (bool strip)
     {
-        Directory.Delete (OutputPath, true);
+        try {
+            Directory.Delete (OutputPath, true);
+        } catch (DirectoryNotFoundException) {
+        }
+
         Directory.CreateDirectory (OutputPath);
 
         foreach (var item in Items) {
-            var path = item.File.FullName;
-            if (ConfinementRoot != null) {
-                path = path.Substring (ConfinementRoot.Length + 1);
+            try {
+                item.Relocate ();
+            } catch {
             }
-            path = Path.Combine (OutputPath, path);
+            /*var native_item = item as NativeLibraryItem;
+            if (strip && native_item != null) {
+                native_item.Strip ();
+            }*/
+        }
 
-            Directory.CreateDirectory (Path.GetDirectoryName (path));
-            if (!strip || !(item is NativeLibraryItem) ||
-                !StripBinary (item.File.FullName, path)) {
-                File.Copy (item.File.FullName, path);
+        int count = 0;
+        foreach (var item in Items) {
+            var native_item = item as NativeLibraryItem;
+            if (native_item != null) {
+                count++;
+                native_item.RelocateDependencies ();
             }
         }
-    }
 
-    private static bool StripBinary (string source, string target)
-    {
-        return ProcessTools.CreateProcess ("strip",
-            String.Format ("-u -r -o \"{1}\" \"{0}\"", source, target)) != null;
+        Console.WriteLine ("{0} native libraries processed.", count);
     }
 }
diff --git a/build/bundle/solitary/SymlinkItem.cs b/build/bundle/solitary/SymlinkItem.cs
new file mode 100644
index 0000000..d00a8dd
--- /dev/null
+++ b/build/bundle/solitary/SymlinkItem.cs
@@ -0,0 +1,68 @@
+// 
+// SymlinkItem.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2009-2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+using Mono.Unix;
+
+public class SymlinkItem : Item
+{
+    private UnixSymbolicLinkInfo link;
+    
+    public static bool IsSymlink (string path)
+    {
+        return new UnixSymbolicLinkInfo (path).HasContents;
+    }
+
+    public override IEnumerable<Item> Load ()
+    {
+        if (!IsValidConfinementItem (this)) {
+            yield break;
+        }
+
+        link = new UnixSymbolicLinkInfo (File.FullName);
+        if (!link.HasContents) {
+            yield break;
+        }
+
+        yield return this;
+        yield return Item.Resolve (Confinement,
+            new FileInfo (link.GetContents ().FullName));
+    }
+
+    public override void Relocate ()
+    {
+        var link_path = GetRelocationPath ();
+        var link_contents_path = PathExtensions.RelativePath (
+            link.GetContents ().FullName,
+            Path.GetDirectoryName (File.FullName));
+        Directory.CreateDirectory (Path.GetDirectoryName (link_path));
+        Console.WriteLine ("Creating {0}", link_path);
+        new UnixSymbolicLinkInfo (link_path).CreateSymbolicLinkTo (link_contents_path);
+    }
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]