/// <summary> /// Sets the list of implementation directories in a specific configuration file. /// </summary> /// <param name="configPath">The path of the configuration file to write.</param> /// <param name="paths">The list of implementation directories to set.</param> /// <exception cref="IOException">There was a problem writing <paramref name="configPath"/>.</exception> /// <exception cref="UnauthorizedAccessException">Access to <paramref name="configPath"/> was not permitted.</exception> private static void SetDirectories(string configPath, IEnumerable <string> paths) { #region Sanity checks if (string.IsNullOrEmpty(configPath)) { throw new ArgumentNullException(nameof(configPath)); } if (paths == null) { throw new ArgumentNullException(nameof(paths)); } #endregion using var atomic = new AtomicWrite(configPath); using (var configFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding) { NewLine = "\n" }) { foreach (string path in paths) { configFile.WriteLine(path); } } atomic.Commit(); }
/// <summary> /// Adds a directory prefix to all entries in an external flag file. /// </summary> /// <param name="path">The full path to the flag file, named <see cref="FlagUtils.XbitFile"/> or <see cref="FlagUtils.SymlinkFile"/>.</param> /// <param name="source">The old path of the renamed file or directory relative to <paramref name="path"/>.</param> /// <param name="destination">The new path of the renamed file or directory relative to <paramref name="path"/>.</param> /// <exception cref="ArgumentException"><paramref name="source"/> or <paramref name="destination"/> is not a relative path.</exception> /// <exception cref="IOException">There was an error writing the flag file.</exception> /// <exception cref="UnauthorizedAccessException">You have insufficient rights to write the flag file.</exception> public static void Rename([NotNull] string path, [NotNull] string source, [NotNull] string destination) { #region Sanity checks if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } if (string.IsNullOrEmpty(source)) { throw new ArgumentNullException("source"); } if (Path.IsPathRooted(source)) { throw new ArgumentException(Resources.PathNotRelative, "source"); } if (string.IsNullOrEmpty(destination)) { throw new ArgumentNullException("destination"); } if (Path.IsPathRooted(destination)) { throw new ArgumentException(Resources.PathNotRelative, "destination"); } #endregion if (!File.Exists(path)) { return; } // Convert paths to rooted Unix-style source = "/" + source.Replace(Path.DirectorySeparatorChar, '/'); destination = "/" + destination.Replace(Path.DirectorySeparatorChar, '/'); using (var atomic = new AtomicWrite(path)) using (var newFlagFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding) { NewLine = "\n" }) using (var oldFlagFile = File.OpenText(path)) { // Each line in the file signals a flagged file while (!oldFlagFile.EndOfStream) { string line = oldFlagFile.ReadLine(); if (line != null && line.StartsWith("/")) { if (line == source || line.StartsWith(source + "/")) { newFlagFile.WriteLine(destination + line.Substring(source.Length)); } else { newFlagFile.WriteLine(line); } } } atomic.Commit(); } }
/// <inheritdoc/> public string GetIcon(Uri iconUrl, ITaskHandler handler) { #region Sanity checks if (iconUrl == null) { throw new ArgumentNullException(nameof(iconUrl)); } if (handler == null) { throw new ArgumentNullException(nameof(handler)); } #endregion string path = Path.Combine(DirectoryPath, new FeedUri(iconUrl).Escape()); // Prevent file-exists race conditions lock (_lock) { // Download missing icons if (!File.Exists(path)) { using (var atomic = new AtomicWrite(path)) { handler.RunTask(new DownloadFile(iconUrl, atomic.WritePath)); atomic.Commit(); } } } return(path); }
private void InitializeEventJournal(TIdentity aggregateId, params IAggregateEvent <TAggregate, TIdentity>[] events) { var writerGuid = Guid.NewGuid().ToString(); var writes = new AtomicWrite[events.Length]; for (var i = 0; i < events.Length; i++) { var committedEvent = new CommittedEvent <TAggregate, TIdentity, IAggregateEvent <TAggregate, TIdentity> >(aggregateId, events[i], new Metadata(), DateTimeOffset.UtcNow, i + 1); writes[i] = new AtomicWrite(new Persistent(committedEvent, i + 1, aggregateId.Value, string.Empty, false, ActorRefs.NoSender, writerGuid)); } var journal = Persistence.Instance.Apply(_testKit.Sys).JournalFor(null); journal.Tell(new WriteMessages(writes, AggregateTestProbe.Ref, 1)); AggregateTestProbe.ExpectMsg <WriteMessagesSuccessful>(); for (var i = 0; i < events.Length; i++) { var seq = i; AggregateTestProbe.ExpectMsg <WriteMessageSuccess>(x => x.Persistent.PersistenceId == aggregateId.ToString() && x.Persistent.Payload is CommittedEvent <TAggregate, TIdentity, IAggregateEvent <TAggregate, TIdentity> > && x.Persistent.SequenceNr == (long)seq + 1); } }
/// <summary> /// Writes the entire content of a byte array to file atomically. /// </summary> /// <param name="data">The data to write.</param> /// <param name="path">The file to write to.</param> private void WriteToFile(byte[] data, string path) { lock (_replaceLock) using (var atomic = new AtomicWrite(path)) { File.WriteAllBytes(atomic.WritePath, data); atomic.Commit(); } }
private void Download(Uri href, string path) { using var atomic = new AtomicWrite(path); _handler.RunTask(new DownloadFile(href, atomic.WritePath) { BytesMaximum = MaximumIconSize }); atomic.Commit(); }
private Proto.Msg.AtomicWrite GetAtomicWrite(AtomicWrite write) { var message = new Proto.Msg.AtomicWrite(); foreach (var pr in (IImmutableList <IPersistentRepresentation>)write.Payload) { message.Payload.Add(GetPersistentMessage(pr)); } return(message); }
/// <summary> /// Saves the settings to an INI file. /// </summary> /// <remarks>This method performs an atomic write operation when possible.</remarks> /// <exception cref="IOException">A problem occurred while writing the file.</exception> /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception> public void Save(string path) { TransferToIni(); Log.Debug("Saving Config to: " + path); using var atomic = new AtomicWrite(path); using (var writer = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding)) new StreamIniDataParser().WriteData(writer, _iniData); atomic.Commit(); }
private CheckAndMutateRowRequest ToBigtableWriteRequest(AtomicWrite atomicWrite, ActorSystem actorSystem) { if (atomicWrite.HighestSequenceNr != atomicWrite.LowestSequenceNr) { throw new NotSupportedException("Journal does not support multiple events in a single atomic write"); } var persistent = ((IImmutableList <IPersistentRepresentation>)atomicWrite.Payload).Single(); return(ToMutateRowIfNotExistsRequest(persistent, actorSystem)); }
private global::AtomicWrite.Builder AtomicWriteToProto(AtomicWrite aw) { var builder = global::AtomicWrite.CreateBuilder(); foreach (var p in (IEnumerable <IPersistentRepresentation>)aw.Payload) { builder.AddPayload(PersistentToProto(p)); } return(builder); }
/// <summary> /// Removes one or more flags for a file or directory in an external flag file. /// </summary> /// <param name="path">The full path to the flag file, named <see cref="FlagUtils.XbitFile"/> or <see cref="FlagUtils.SymlinkFile"/>.</param> /// <param name="relativePath">The path of the file or directory to remove relative to <paramref name="path"/>.</param> /// <exception cref="ArgumentException"><paramref name="relativePath"/> is not a relative path.</exception> /// <exception cref="IOException">There was an error writing the flag file.</exception> /// <exception cref="UnauthorizedAccessException">You have insufficient rights to write the flag file.</exception> public static void Remove([NotNull] string path, [NotNull] string relativePath) { #region Sanity checks if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } if (string.IsNullOrEmpty(relativePath)) { throw new ArgumentNullException("relativePath"); } if (Path.IsPathRooted(relativePath)) { throw new ArgumentException(Resources.PathNotRelative, "relativePath"); } #endregion if (!File.Exists(path)) { return; } // Convert path to rooted Unix-style string unixPath = "/" + relativePath.Replace(Path.DirectorySeparatorChar, '/'); using (var atomic = new AtomicWrite(path)) using (var newFlagFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding) { NewLine = "\n" }) using (var oldFlagFile = File.OpenText(path)) { // Each line in the file signals a flagged file while (!oldFlagFile.EndOfStream) { string line = oldFlagFile.ReadLine(); if (line != null && line.StartsWith("/")) { if (line == unixPath || line.StartsWith(unixPath + "/")) { continue; // Filter out removed files } newFlagFile.WriteLine(line); } } atomic.Commit(); } }
/// <summary> /// Saves an object in an XML file ending with a line break. /// </summary> /// <remarks>This method performs an atomic write operation when possible.</remarks> /// <typeparam name="T">The type of object to be saved in an XML stream.</typeparam> /// <param name="data">The object to be stored.</param> /// <param name="path">The path of the file to write.</param> /// <param name="stylesheet">The path of an XSL stylesheet for <typeparamref name="T"/>; can be <c>null</c>.</param> /// <exception cref="IOException">A problem occurred while writing the file.</exception> /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception> /// <remarks>Uses <seealso cref="AtomicWrite"/> internally.</remarks> public static void SaveXml <T>([NotNull] this T data, [NotNull, Localizable(false)] string path, [CanBeNull, Localizable(false)] string stylesheet = null) { #region Sanity checks if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } #endregion using (var atomic = new AtomicWrite(path)) { using (var fileStream = File.Create(atomic.WritePath)) SaveXml(data, fileStream, stylesheet); atomic.Commit(); } }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed private async Task WriteBatchAsync(AtomicWrite aw) { var transaction = Database.CreateTransaction(); var payloads = aw.Payload.AsInstanceOf <IImmutableList <IPersistentRepresentation> >(); foreach (var payload in payloads) { var(bytes, tags) = Extract(payload); // save the payload transaction.SortedSetAddAsync(_journalHelper.GetJournalKey(payload.PersistenceId), bytes, payload.SequenceNr); // notify about a new event being appended for this persistence id transaction.PublishAsync(_journalHelper.GetJournalChannel(payload.PersistenceId), payload.SequenceNr); // save tags foreach (var tag in tags) { transaction.ListRightPushAsync(_journalHelper.GetTagKey(tag), $"{payload.SequenceNr}:{payload.PersistenceId}"); transaction.PublishAsync(_journalHelper.GetTagsChannel(), tag); } } // set highest sequence number key transaction.StringSetAsync(_journalHelper.GetHighestSequenceNrKey(aw.PersistenceId), aw.HighestSequenceNr); // add persistenceId transaction.SetAddAsync(_journalHelper.GetIdentifiersKey(), aw.PersistenceId).ContinueWith(task => { if (task.Result) { // notify about a new persistenceId Database.Publish(_journalHelper.GetIdentifiersChannel(), aw.PersistenceId); } }); if (!await transaction.ExecuteAsync()) { throw new Exception($"{nameof(WriteMessagesAsync)}: failed to write {typeof(IPersistentRepresentation).Name} to redis"); } }
/// <summary> /// Saves an object in an XML file embedded in a ZIP archive. /// </summary> /// <typeparam name="T">The type of object to be saved in an XML stream.</typeparam> /// <param name="data">The object to be stored.</param> /// <param name="path">The ZIP archive to be written.</param> /// <param name="password">The password to use for encryption; <c>null</c> for no encryption.</param> /// <param name="additionalFiles">Additional files to be stored alongside the XML file in the ZIP archive; can be <c>null</c>.</param> /// <exception cref="IOException">A problem occurred while writing the file.</exception> /// <exception cref="UnauthorizedAccessException">Write access to the file is not permitted.</exception> /// <remarks>Uses <seealso cref="AtomicWrite"/> internally.</remarks> public static void SaveXmlZip <T>([NotNull] this T data, [NotNull, Localizable(false)] string path, [CanBeNull, Localizable(false)] string password = null, [NotNull] params EmbeddedFile[] additionalFiles) { #region Sanity checks if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } if (additionalFiles == null) { throw new ArgumentNullException(nameof(additionalFiles)); } #endregion using (var atomic = new AtomicWrite(path)) { using (var fileStream = File.Create(atomic.WritePath)) SaveXmlZip(data, fileStream, password, additionalFiles); atomic.Commit(); } }
public void Journal_should_serialize_events() { if (!SupportsSerialization) { return; } var probe = CreateTestProbe(); var @event = new TestPayload(probe.Ref); var aw = new AtomicWrite( new Persistent(@event, 6L, Pid, sender: ActorRefs.NoSender, writerGuid: WriterGuid)); Journal.Tell(new WriteMessages(new [] { aw }, probe.Ref, ActorInstanceId)); probe.ExpectMsg <WriteMessagesSuccessful>(); var pid = Pid; var writerGuid = WriterGuid; probe.ExpectMsg <WriteMessageSuccess>(o => { Assertions.AssertEqual(writerGuid, o.Persistent.WriterGuid); Assertions.AssertEqual(pid, o.Persistent.PersistenceId); Assertions.AssertEqual(6L, o.Persistent.SequenceNr); Assertions.AssertTrue(o.Persistent.Sender == ActorRefs.NoSender || o.Persistent.Sender.Equals(Sys.DeadLetters), $"Expected WriteMessagesSuccess.Persistent.Sender to be null or {Sys.DeadLetters}, but found {o.Persistent.Sender}"); Assertions.AssertEqual(@event, o.Persistent.Payload); }); Journal.Tell(new ReplayMessages(6L, long.MaxValue, long.MaxValue, Pid, _receiverProbe.Ref)); _receiverProbe.ExpectMsg <ReplayedMessage>(o => { Assertions.AssertEqual(writerGuid, o.Persistent.WriterGuid); Assertions.AssertEqual(pid, o.Persistent.PersistenceId); Assertions.AssertEqual(6L, o.Persistent.SequenceNr); Assertions.AssertTrue(o.Persistent.Sender == ActorRefs.NoSender || o.Persistent.Sender.Equals(Sys.DeadLetters), $"Expected WriteMessagesSuccess.Persistent.Sender to be null or {Sys.DeadLetters}, but found {o.Persistent.Sender}"); Assertions.AssertEqual(@event, o.Persistent.Payload); }); Assertions.AssertEqual(_receiverProbe.ExpectMsg <RecoverySuccess>().HighestSequenceNr, 6L); }
/// <summary> /// Sets the list of catalog sources in a configuration file. /// </summary> /// <param name="uris">The list of catalog sources to use from now on.</param> /// <exception cref="IOException">There was a problem writing a configuration file.</exception> /// <exception cref="UnauthorizedAccessException">Access to a configuration file was not permitted.</exception> public static void SetSources(IEnumerable <FeedUri> uris) { #region Sanity checks if (uris == null) { throw new ArgumentNullException(nameof(uris)); } #endregion using var atomic = new AtomicWrite(Locations.GetSaveConfigPath("0install.net", true, "catalog-sources")); using (var configFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding) { NewLine = "\n" }) { foreach (var uri in uris) { configFile.WriteLine(uri.ToStringRfc()); } } atomic.Commit(); }
/// <summary> /// Builds a stub EXE that executes the "0install run" command at a specific path. /// </summary> /// <param name="path">The path to store the generated EXE file.</param> /// <param name="target">The application to be launched.</param> /// <param name="command">The command argument to be passed to the the "0install run" command; can be <c>null</c>.</param> /// <param name="gui"><c>true</c> to build a GUI stub, <c>false</c> to build a CLI stub.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="InvalidOperationException">There was a compilation error while generating the stub EXE.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem is not permitted.</exception> public void BuildRunStub(string path, FeedTarget target, string?command = null, bool gui = false) { #region Sanity checks if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } #endregion var compilation = CSharpCompilation.Create( assemblyName: "ZeroInstall.Stub", syntaxTrees: new[] { GetCode( exe: GetExe(gui), arguments: GetArguments(target.Uri, command, gui), title: target.Feed.GetBestName(CultureInfo.CurrentUICulture, command)) }, _references, options: new( gui ? OutputKind.WindowsApplication : OutputKind.ConsoleApplication, optimizationLevel: OptimizationLevel.Release, deterministic: true)); var resources = GetResources(compilation, GetIconPath(target, command)); using var atomic = new AtomicWrite(path); using (var stream = File.Create(atomic.WritePath)) { var result = compilation.Emit(stream, win32Resources: resources); if (!result.Success) { throw new IOException(result.Diagnostics.FirstOrDefault()?.ToString()); } } atomic.Commit(); }
/// <summary> /// Sets the list of implementation directory paths in the current user configuration. /// </summary> /// <param name="paths">The list of implementation directory paths to set.</param> /// <exception cref="IOException">There was a problem writing a configuration file.</exception> /// <exception cref="UnauthorizedAccessException">Access to a configuration file was not permitted.</exception> public static void SetUserCustomImplementationDirs([NotNull, ItemNotNull, InstantHandle] IEnumerable <string> paths) { #region Sanity checks if (paths == null) { throw new ArgumentNullException("paths"); } #endregion using (var atomic = new AtomicWrite(Locations.GetSaveConfigPath("0install.net", true, "injector", "implementation-dirs"))) { using (var configFile = new StreamWriter(atomic.WritePath, append: false, encoding: FeedUtils.Encoding) { NewLine = "\n" }) { foreach (var path in paths) { configFile.WriteLine(path); } } atomic.Commit(); } }
/// <summary> /// Writes the entire content of a byte array to file atomically. /// </summary> /// <param name="data">The data to write.</param> /// <param name="path">The file to write to.</param> private static void WriteToFile(byte[] data, string path) { using var atomic = new AtomicWrite(path); File.WriteAllBytes(atomic.WritePath, data); atomic.Commit(); }
private global::AtomicWrite.Builder AtomicWriteToProto(AtomicWrite aw) { var builder = global::AtomicWrite.CreateBuilder(); foreach (var p in (IEnumerable<IPersistentRepresentation>)aw.Payload) { builder.AddPayload(PersistentToProto(p)); } return builder; }