internal Package GetProvider(Uri uri) { return new Package(this, uri.SingleItemAsEnumerable()); }
internal static Task<RecognitionInfo> Recognize(string item, bool forceRescan = false) { var cachedResult = SessionCache<RecognitionInfo>.Value[item]; if (cachedResult != null) { if (forceRescan) { SessionCache<RecognitionInfo>.Value[item] = null; } else { return cachedResult.AsResultTask(); } } try { var location = new Uri(item); if (!location.IsFile) { // some sort of remote item. // since we can't do anything with a remote item directly, // we have to issue a request to the client to get it for us // before we go down this, check to see if we asked for it in this session // in the last five minutes or so. We don't need to pound away at a URL for // no reason. var peek = SessionCache<RecognitionInfo>.Value[location.AbsoluteUri]; if( peek != null ) { if( DateTime.Now.Subtract(peek.LastAccessed) < new TimeSpan(0,5,0) ) { return peek.AsResultTask(); } } // since we're expecting that the canonicalname will be used as a filename // in the .cache directory, we need to generate a safe filename based on the // data in the URL var safeCanonicalName = location.GetLeftPart(UriPartial.Path).MakeSafeFileName(); // BEFORE // Check to see if there is a request for this file already in progress. // attach a continuation to that if it is, instead of adding a new task Task<RecognitionInfo> completion; lock (SessionCache<Task<RecognitionInfo>>.Value) { completion = SessionCache<Task<RecognitionInfo>>.Value[safeCanonicalName]; if (completion != null) { return completion.ContinueAlways(antecedent => antecedent.Result); } // otherwise, let's create a delegate to run when the file gets resolved. completion = new Task<RecognitionInfo>(rrfState => { var state = rrfState as RequestRemoteFileState; if (state == null || string.IsNullOrEmpty(state.LocalLocation)) { // didn't fill in the local location? -- this happens when the client can't download. // PackageManagerMessages.Invoke.FileNotRecognized() ? var rslt = new RecognitionInfo { FullPath = location.AbsoluteUri, FullUrl = location, IsURL = true, IsInvalid = true, }; // session cache it SessionCache<RecognitionInfo>.Value[location.AbsoluteUri] = rslt; return rslt; } var newLocation = new Uri(state.LocalLocation); if (newLocation.IsFile) { var continuedResult = Recognize(state.LocalLocation).Result; // create the result object var result = new RecognitionInfo { FullUrl = location, }; // if( continuedResult.IsPackageFeed && forceRescan ) { // this ensures that feed files aren't kept around needlessly. //state.LocalLocation.MarkFileTemporary(); //} result.CopyDetailsFrom(continuedResult); result.IsURL = true; return Cache(item, result); } // so, the callback comes, but it's not a file. // var r = new RecognitionInfo { FullPath = location.AbsoluteUri, IsInvalid = true, }; // session cache it SessionCache<RecognitionInfo>.Value[location.AbsoluteUri] = r; return r; }, new RequestRemoteFileState { OriginalUrl = location.AbsoluteUri }, TaskCreationOptions.AttachedToParent); // store the task until the client tells us that it has the file. SessionCache<Task<RecognitionInfo>>.Value[safeCanonicalName] = completion; } // GS01: Should we make a deeper path in the cache directory? // perhaps that would let us use a cached version of the file we're looking for. Event<GetResponseInterface>.RaiseFirst().RequireRemoteFile(safeCanonicalName, location.SingleItemAsEnumerable(),PackageManagerSettings.CoAppPackageCache, forceRescan); // return the completion task, as whatever is waiting for this // needs to continue on that. return completion; } //---------------------------------------------------------------- // we've managed to find a file system path. // let's figure out what it is. var localPath = location.LocalPath; if (localPath.Contains("?") || localPath.Contains("*")) { // looks like a wildcard package feed. // which is a directory feed with a filter. var i = localPath.IndexOfAny(new[] {'*', '?'}); var lastSlash = localPath.LastIndexOf('\\', i); var folder = localPath.Substring(0, lastSlash); if (Directory.Exists(folder)) { return CacheAndReturnTask(item, new RecognitionInfo { FullPath = folder, Filter = localPath.Substring(lastSlash + 1), IsFolder = true, IsPackageFeed = true }); } } if (Directory.Exists(localPath)) { // it's a directory. // which means that it's a package feed. return CacheAndReturnTask(item, new RecognitionInfo { FullPath = localPath, Filter = "*", IsFolder = true, IsPackageFeed = true, }); } if (File.Exists(localPath)) { var ext = Path.GetExtension(localPath); var result = new RecognitionInfo { IsFile = true, FullPath = localPath }; switch (ext) { case ".msi": result.IsCoAppMSI = CoAppMSI.IsValidPackageFile(localPath); result.IsLegacyMSI = !result.IsCoAppMSI; result.IsPackageFile = true; break; case ".nupkg": result.IsNugetPackage = true; result.IsPackageFile = true; break; case ".exe": result.IsLegacyEXE = true; result.IsPackageFile = true; break; case ".zip": case ".cab": case ".rar": case ".7z": result.IsArchive = true; result.IsPackageFeed = true; break; default: // guess based on file contents try { if (CoAppMSI.IsValidPackageFile(localPath)) { result.IsCoAppMSI = true; result.IsPackageFile = true; } } catch { // not a coapp file... } if (localPath.IsXmlFile()) { try { // this could be an atom feed var feed = AtomFeed.LoadFile(localPath); if (feed != null) { result.IsPackageFeed = true; result.IsAtom = true; } } catch { // can't seem to figure out what this is. result.IsInvalid = true; } } break; } return CacheAndReturnTask(item, result); } } catch (UriFormatException) { } // item wasn't able to match any known URI, UNC or Local Path format. // or was file not found return new RecognitionInfo { FullPath = item, IsInvalid = true, }.AsResultTask(); }
internal static Task<RecognitionInfo> Recognize(string item, bool forceRescan = false) { var cachedResult = SessionData.Current.RecognitionInfo[item]; if (cachedResult != null) { if (forceRescan) { SessionData.Current.RecognitionInfo[item] = null; } else { return cachedResult.AsResultTask(); } } try { var location = new Uri(item); if (!location.IsFile) { // some sort of remote item. // since we can't do anything with a remote item directly, // we have to issue a request to the client to get it for us // before we go down this, check to see if we asked for it in this session // in the last five minutes or so. We don't need to pound away at a URL for // no reason. var peek = SessionData.Current.RecognitionInfo[location.AbsoluteUri]; if( peek != null ) { if( DateTime.Now.Subtract(peek.LastAccessed) < new TimeSpan(0,5,0) ) { return peek.AsResultTask(); } } // since we're expecting that the canonicalname will be used as a filename // in the .cache directory, we need to generate a safe filename based on the // data in the URL var safeCanonicalName = location.GetLeftPart(UriPartial.Path).MakeSafeFileName(); return SessionData.Current.RequireRemoteFile(safeCanonicalName, location.SingleItemAsEnumerable(), PackageManagerSettings.CoAppPackageCache, forceRescan, state => { if (state == null || string.IsNullOrEmpty(state.LocalLocation)) { // didn't fill in the local location? -- this happens when the client can't download. return Cache(location.AbsoluteUri, new RecognitionInfo { FullPath = location.AbsoluteUri, FullUrl = location, IsURL = true, IsInvalid = true, }); } var newLocation = new Uri(state.LocalLocation); if (newLocation.IsFile) { var continuedResult = Recognize(state.LocalLocation).Result; // create the result object var result = new RecognitionInfo { FullUrl = location, }; result.CopyDetailsFrom(continuedResult); result.IsURL = true; return Cache(item, result); } // so, the callback comes, but it's not a file. // session cache it return Cache(location.AbsoluteUri,new RecognitionInfo { FullPath = location.AbsoluteUri, IsInvalid = true, }); }) as Task<RecognitionInfo>; } //---------------------------------------------------------------- // we've managed to find a file system path. // let's figure out what it is. var localPath = location.LocalPath; if (localPath.Contains("?") || localPath.Contains("*")) { // looks like a wildcard package feed. // which is a directory feed with a filter. var i = localPath.IndexOfAny(new[] {'*', '?'}); var lastSlash = localPath.LastIndexOf('\\', i); var folder = localPath.Substring(0, lastSlash); if (Directory.Exists(folder)) { return CacheAndReturnTask(item, new RecognitionInfo { FullPath = folder, Filter = localPath.Substring(lastSlash + 1), IsFolder = true, IsPackageFeed = true }); } } if (Directory.Exists(localPath)) { // it's a directory. // which means that it's a package feed. return CacheAndReturnTask(item, new RecognitionInfo { FullPath = localPath, Filter = "*.msi", // TODO: evenutally, we have to expand this to detect other types. IsFolder = true, IsPackageFeed = true, }); } if (File.Exists(localPath)) { var ext = Path.GetExtension(localPath); var result = new RecognitionInfo { IsFile = true, FullPath = localPath }; switch (ext) { case ".msi": result.IsCoAppMSI = CoAppMSI.IsValidPackageFile(localPath); result.IsLegacyMSI = !result.IsCoAppMSI; result.IsPackageFile = true; break; case ".nupkg": result.IsNugetPackage = true; result.IsPackageFile = true; break; case ".exe": result.IsLegacyEXE = true; result.IsPackageFile = true; break; case ".zip": case ".cab": case ".rar": case ".7z": result.IsArchive = true; result.IsPackageFeed = true; break; default: // guess based on file contents try { if (CoAppMSI.IsValidPackageFile(localPath)) { result.IsCoAppMSI = true; result.IsPackageFile = true; } } catch { // not a coapp file... } if (localPath.IsXmlFile()) { try { // this could be an atom feed var feed = AtomFeed.LoadFile(localPath); if (feed != null) { result.IsPackageFeed = true; result.IsAtom = true; } } catch { // can't seem to figure out what this is. result.IsInvalid = true; } } break; } return CacheAndReturnTask(item, result); } } catch (UriFormatException) { } // item wasn't able to match any known URI, UNC or Local Path format. // or was file not found return new RecognitionInfo { FullPath = item, IsInvalid = true, }.AsResultTask(); }