diff options
author | Miguel de Icaza <miguel@gnome.org> | 2013-10-11 01:46:00 +0400 |
---|---|---|
committer | Miguel de Icaza <miguel@gnome.org> | 2013-10-11 01:46:00 +0400 |
commit | 80ee5ae51dc9418d1e6bc044e8fd3515be55f75b (patch) | |
tree | 87c1f5bc0ba4703e720388ce34ab5789370e232c | |
parent | 0c582899f4dbe7d535e904ba4060d0cbe193cc3a (diff) |
Simplify the mac documentation updating
-rw-r--r-- | AppDelegate.cs | 92 | ||||
-rw-r--r-- | AppleDocHandler.cs | 154 | ||||
-rw-r--r-- | Product.cs | 12 | ||||
-rw-r--r-- | macdoc.csproj | 1 |
4 files changed, 41 insertions, 218 deletions
diff --git a/AppDelegate.cs b/AppDelegate.cs index 3b33091..b7d584f 100644 --- a/AppDelegate.cs +++ b/AppDelegate.cs @@ -13,6 +13,7 @@ using MonoMac.AppKit; using MonoMac.ObjCRuntime; using Monodoc; +using System.Text; namespace macdoc { @@ -106,9 +107,21 @@ namespace macdoc IndexUpdateManager = new IndexUpdateManager (helpSources, macDocPath); BookmarkManager = new BookmarkManager (macDocPath); - AppleDocHandler = new AppleDocHandler ("/Library/Frameworks/Mono.framework/Versions/Current/etc/"); } - + + int Run (string command) + { + var psi = new System.Diagnostics.ProcessStartInfo (command, " --need-update"); + var t = ProcessUtils.StartProcess (psi, null, null, CancellationToken.None); + t.Wait (); + + try { + return t.Result; + } catch { + return 1; + } + } + public override void FinishedLaunching (NSObject notification) { // Check if we are loaded with a search term and load a document for it @@ -133,25 +146,23 @@ namespace macdoc // Check if there is a MonoTouch/MonoMac documentation installed and launch accordingly var products = Root.HelpSources.Where (hs => hs != null && hs.Name != null).ToProducts ().Distinct ().ToArray (); - if (products.Where (p => File.Exists (ProductUtils.GetMergeToolForProduct (p))).Any ()) { - Task.Factory.StartNew (() => { - return products.ToDictionary (p => p, - p => { - AppleDocHandler.AppleDocInformation infos; - bool mergeOutdated = false; - bool docOutdated = AppleDocHandler.CheckAppleDocFreshness (ProductUtils.GetDocFeedForProduct (p), - out infos); - if (!docOutdated) - mergeOutdated = AppleDocHandler.CheckMergedDocumentationFreshness (infos, p); - return Tuple.Create (docOutdated, mergeOutdated); - }); - }).ContinueWith (t => { - Logger.Log ("Merged status {0}", string.Join (", ", t.Result.Select (kvp => kvp.ToString ()))); - if (!t.Result.Any (kvp => kvp.Value.Item1 || kvp.Value.Item2)) - return; - BeginInvokeOnMainThread (() => LaunchDocumentationUpdate (t.Result)); - }); + var message = new StringBuilder ("We have detected that your documentation for the following products can be improved by merging the Apple documentation:\n"); + var toUpdate = new List<Product> (); + foreach (var p in products) { + bool needUpdate = false; + var tool = ProductUtils.GetMergeToolForProduct (p); + + if (!File.Exists (tool)) + continue; + + if (Run (tool) == 0) { + toUpdate.Add (p); + message.AppendFormat ("{0}\n", ProductUtils.GetFriendlyName (p)); + } } + + if (toUpdate.Count > 0) + LaunchDocumentationUpdate (toUpdate.ToArray (), message.ToString ()); } public static IndexUpdateManager IndexUpdateManager { @@ -163,12 +174,7 @@ namespace macdoc get; private set; } - - public static AppleDocHandler AppleDocHandler { - get; - private set; - } - + public static bool IsOnLionOrBetter { get { return isOnLion; @@ -246,19 +252,12 @@ namespace macdoc IntPtr.Zero); } - void LaunchDocumentationUpdate (Dictionary<Product, Tuple<bool, bool>> toUpdate) + void LaunchDocumentationUpdate (Product [] products, string informative) { - var outdatedProducts = string.Join (" and ", toUpdate.Where (kvp => kvp.Value.Item1 || kvp.Value.Item2).Select (kvp => ProductUtils.GetFriendlyName (kvp.Key))); - var informative = "We have detected your " + outdatedProducts + " documentation can be upgraded with Apple documentation."; - // Check if we are going to be downloading stuff - if (toUpdate.Any (kvp => kvp.Value.Item1)) - informative += Environment.NewLine + Environment.NewLine + "Warning: we are going to download documentation from Apple servers which can take a long time depending on your Internet connection."; - informative += Environment.NewLine + Environment.NewLine + "Would you like to update the documentation now?"; - var infoDialog = new NSAlert { AlertStyle = NSAlertStyle.Informational, MessageText = "Documentation update available", - InformativeText = informative + InformativeText = informative + "\n\nWarning: If you have not downloaded the documentation with Xcode, this program will download the documentation from Apple servers which can take a long time.\n\nWould you like to update the documentation now?" }; infoDialog.AddButton ("Update now"); @@ -267,23 +266,14 @@ namespace macdoc // If Cancel was clicked, just return if (dialogResult == (int)NSAlertButtonReturn.Second) return; - - // Launching AppleDocWizard as root - var mergerTasks = toUpdate - .Where (kvp => kvp.Value.Item1 || kvp.Value.Item2) - .Select (kvp => Task.Factory.StartNew (() => { - var mergeToolPath = ProductUtils.GetMergeToolForProduct (kvp.Key); - var docOutdated = kvp.Value.Item1; - // If the script has its setuid bit on and user as root, then we launch it directly otherwise we first restore it - if (!RootLauncher.IsRootEnabled (mergeToolPath)) { - RootLauncher.LaunchExternalTool (mergeToolPath, new string[] { "--self-repair" }); - // No good way to know when the process will finish, so wait a bit. Not ideal but since this is an unlikely codepath, shouldn't matter. - System.Threading.Thread.Sleep (1000); - } - var psi = new System.Diagnostics.ProcessStartInfo (mergeToolPath, docOutdated ? "--force-download" : null); - return ProcessUtils.StartProcess (psi, null, null, CancellationToken.None); - }).Unwrap ()); + var mergerTasks = products.Select (p => Task.Factory.StartNew (() => { + var mergeToolPath = ProductUtils.GetMergeToolForProduct (p); + + var psi = new System.Diagnostics.ProcessStartInfo (mergeToolPath, null); + return ProcessUtils.StartProcess (psi, null, null, CancellationToken.None); + }).Unwrap ()); + // No Task.WhenAll yet var tcs = new TaskCompletionSource<int> (); Task.Factory.ContinueWhenAll (mergerTasks.ToArray (), ts => { diff --git a/AppleDocHandler.cs b/AppleDocHandler.cs deleted file mode 100644 index 4917cb2..0000000 --- a/AppleDocHandler.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.IO; -using System.Net; -using System.Linq; -using System.Threading; -using System.Xml.Linq; -using System.Collections.Generic; - -namespace macdoc -{ - public class AppleDocHandler - { - public class AppleDocInformation - { - public Version Version { get; set; } - public string ID { get; set; } - public DateTime UpdateDate { get; set; } - public string DownloadUrl { get; set; } - } - - readonly string[] searchPaths = new[] { - "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Documentation/DocSets", - "/Applications/Xcode.app/Contents/Developer/Documentation/DocSets/", - "/Library/Developer/Shared/Documentation/DocSets/", - "/Developer/Platforms/iPhoneOS.platform/Developer/Documentation/DocSets/" - }; - const string MonodocLibPath = "/Library/Frameworks/Mono.framework/External/monodoc/"; - const string MonoTouchLibPath = "/Developer/MonoTouch/usr/lib/mono/2.1/monotouch.dll"; - - public const string Ios5AtomFeed = "https://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone5_0.atom"; - public const string Ios6AtomFeed = "https://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone6.0.atom"; - public const string MacLionAtomFeed = "http://developer.apple.com/rss/com.apple.adc.documentation.AppleLion.atom"; - public const string MacMountainLionFeed = "https://developer.apple.com/rss/com.apple.adc.documentation.AppleOSX10_8.atom"; - - readonly XNamespace docsetNamespace = "http://developer.apple.com/rss/docset_extensions"; - readonly XNamespace atomNamespace = "http://www.w3.org/2005/Atom"; - readonly string baseApplicationPath; - - Dictionary<string, XDocument> appleFeeds = new Dictionary<string, XDocument> (); - - public AppleDocHandler (string baseApplicationPath) - { - this.baseApplicationPath = baseApplicationPath; - } - - // We load the atom field that contains a timeline of the modifications down to documentation by Apple - XDocument LoadAppleFeed (string feedUrl) - { - XDocument appleFeed; - if (appleFeeds.TryGetValue (feedUrl, out appleFeed)) - return appleFeed; - - WebClient wc = new WebClient (); - var feed = wc.DownloadString (feedUrl); - return appleFeeds[feedUrl] = XDocument.Parse (feed); - } - - // This method transforms the Atom XML data into a POCO for the the most recent item of the feed - AppleDocInformation GetLatestAppleDocInformation (XDocument feed) - { - var latestEntry = feed.Descendants (atomNamespace + "entry").FirstOrDefault (); - if (latestEntry == null) - return null; - - var infos = new AppleDocInformation () { - Version = CloneFillWithZeros (new Version (latestEntry.Element (docsetNamespace + "version").Value)), - ID = latestEntry.Element (docsetNamespace + "identifier").Value, - UpdateDate = DateTime.Parse (latestEntry.Element (atomNamespace + "updated").Value), - DownloadUrl = latestEntry.Element (atomNamespace + "link").Attribute ("href").Value - }; - - return infos; - } - - // This method read the Info.plist available in all Apple .docset to get the version of the bundle - Version GetAppleDocVersion (string directory) - { - var plist = Path.Combine (directory, "Contents", "Info.plist"); - if (!File.Exists (plist)) - return null; - - var doc = XDocument.Load (plist); - var version = doc.Descendants ("key") - .First (k => k.Value.Equals ("CFBundleVersion", StringComparison.Ordinal)) - .ElementsAfterSelf () - .First () - .Value; - - return CloneFillWithZeros (new Version (version)); - } - - // This method checks that an iOS documentation set is installed on the user machine - // and also checks if it's the latest available - bool CheckAppleDocAvailabilityAndFreshness (AppleDocInformation infos) - { - var path = searchPaths - .Select (p => Path.Combine (p, infos.ID + ".docset")) - .FirstOrDefault (p => Directory.Exists (p)); - - if (path == null) - return false; - - var installedVersion = GetAppleDocVersion (path); - Logger.Log ("Installed doc version {0}, compared to remote {1}", installedVersion.ToString (), infos.Version.ToString ()); - return installedVersion >= infos.Version; - } - - // atom feed is one of the Apple documentation feed, iOS and Lion are given in const form above - // returns true if the documentation was updated, false otherwise. The progressDelegate parameter - // is given the completion percentage - public bool CheckAppleDocFreshness (string atomFeed, out AppleDocInformation infos) - { - Logger.Log ("Downloading Apple feed at {0}", atomFeed); - var feed = LoadAppleFeed (atomFeed); - infos = GetLatestAppleDocInformation (feed); - var needRefresh = !CheckAppleDocAvailabilityAndFreshness (infos); - - return needRefresh; - } - - public bool CheckMergedDocumentationFreshness (AppleDocInformation infos, Product product) - { - var statusFile = Path.Combine (baseApplicationPath, "macdoc"); - if (!Directory.Exists (statusFile)) { - try { - Directory.CreateDirectory (statusFile); - } catch {} - return true; - } - statusFile = Path.Combine (statusFile, product == Product.MonoMac ? "merge.mac.status" : "merge.status"); - if (!File.Exists (statusFile)) - return true; - if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("APPLEDOCWIZARD_FORCE_MERGE"))) - return true; - - var mergedVersion = CloneFillWithZeros (new Version (File.ReadAllText (statusFile))); - Logger.Log ("Comparing merged {0} with downloaded {1}", mergedVersion.ToString (), infos.Version.ToString ()); - return mergedVersion != infos.Version; - } - - static Version CloneFillWithZeros (Version v) - { - if (v == null) - return null; - int major = v.Major == -1 ? 0 : v.Major; - int minor = v.Minor == -1 ? 0 : v.Minor; - int build = v.Build == -1 ? 0 : v.Build; - int revision = v.Revision == -1 ? 0 : v.Revision; - - return new Version (major, minor, build, revision); - } - - } -} @@ -35,18 +35,6 @@ namespace macdoc } } - public static string GetDocFeedForProduct (Product product) - { - switch (product) { - case Product.MonoTouch: - return AppleDocHandler.Ios6AtomFeed; - case Product.MonoMac: - return AppleDocHandler.MacMountainLionFeed; - default: - return null; - } - } - public static string GetMergeToolForProduct (Product product) { switch (product) { diff --git a/macdoc.csproj b/macdoc.csproj index 4fce79a..cf9b573 100644 --- a/macdoc.csproj +++ b/macdoc.csproj @@ -100,7 +100,6 @@ <Compile Include="FindBarExtraordinaire.designer.cs"> <DependentUpon>FindBarExtraordinaire.cs</DependentUpon> </Compile> - <Compile Include="AppleDocHandler.cs" /> <Compile Include="ProcessUtils.cs" /> <Compile Include="AppleDocMergeWindow.cs" /> <Compile Include="AppleDocMergeWindowController.cs" /> |