This is the multi-page printable view of this section. Click here to print.
Blog
Version 2.2.3
Version 2.2.3 (build 125) - 20 December 2024
The Verify remote feature is completed. If you are utilizing this feature, please ensure that you verify either
push or pull before disabling the —dry-run
option. This feature is primarily intended for users who have multiple
Macs and synchronize at least two Macs to a remote storage location that is not a Git repository. The function also
requiere version 3.x of rsync to be installed and enabled.
Note: Text button switching --dry-run
mode off is misleading. See Verify remote,
text should be Off, fixed in code.
The majority of the refactoring are internal changes, primarily to move a few tasks to background processes. Moving resource-intensive work to the background thread is advantageous to prevent blocking GUI updates. All updates for the GUI are executed on the main thread.
The following tasks have been refactored to background threads. Writing data to the permanent storage remains on the main thread.
- reading data from the permanent storage
- log records are mapped into a structure fit for viewing
- preparing output from rsync
- output from rsync can often be huge, previous limit of 40K rows has been removed, RsynUI presents as many rows there are
- sorting and filtering log records in view “Log listings”
There are som details about LogRecords and Logs
and Output from rsync.
If there are like 100K lines of output from rsync, which are delivered as an Array of Strings, the Array of Strings
is mapped into a new Array of structs
which are compliance with the Identifiable
protocol. Swift performes, but still
mapping 100K may take a second or two depending on the hardware. If the above mapping is performed on the main thread,
it is a possibility that the spinning beach ball is presented.
For further details on the major changes in this version, please refer to the blog post at blog/2024/12/06/swift-concurrency/.
Additionally, there are a few other enhancements implemented in this version as well.
Swift concurrency
To begin, I must acknowledge that my understanding of Swift concurrency is limited. I am actively learning about Swift and SwiftUI. RsyncUI is a graphical user interface (GUI) application; most of its work is executed on the main thread. However, in version 2.2.3, most resource-intensive tasks are moved from the main thread to background threads. RsyncUI functions effectively as it is, but it also serves as a learning opportunity for new features. Stability is also a crucial aspect of RsyncUI. Consequently, I refrain from releasing new versions until I am confident in its stability.
Swift concurrency and asynchronous execution
Concurrency and asynchronous execution are fundamental concepts in Swift. The latest version of Swift simplifies the writing of asynchronous code
using Swift’s async
and await
keywords, as well as the actor
keyword for executing work on background threads. The Swift concurrency model is
intricate, and it requires dedicated time and study to grasp its fundamentals. Apart from GUI updates, which SwiftUI handles, RsyncUI does not
incorporate concurrency. However, it does support asynchronous execution, but only one task at a time. Each time a rsync
synchronize and restore task is
initiated, its termination is uncertain.
Swift version 6 and the new concurrency model
Swift version 6 introduced strict concurrency checking. By enabling Swift 6 language mode and strict concurrency checking, Xcode assists in identifying and resolving possible data races at compile time.
Quote swift.org: “More formally, a data race occurs when one thread accesses memory while the same memory is being modified by another thread. The Swift 6 language mode eliminates these issues by preventing data races at compile time.”
RsyncUI adheres to the new concurrency model of Swift 6. However, with the release of version 2.2.1 of RsyncUI, the majority of its work is performed on
the @MainActor
, which corresponds to the main thread. If an macOS application performs resource-intensive tasks behind the graphical user interface (GUI),
it is advantageous to execute these tasks on a background thread rather than the main thread. Executing such tasks on the main thread significantly
increases the likelihood of GUI blocking and the application’s unresponsiveness.
RsyncUI Version 2.2.3
In version 2.2.3, the majority of read operations, decoding and encoding data are executed on background threads. Additionally, sorting log records and preparing output from rsync for display are also moved to background threads.
Swift concurrency is exemplified within the log view. Loading log records is performed on a background thread. When the number of log records exceeds 1000, a slight delay is observed before the records appear. Upon completion of the background thread’s work, RsyncUI updates the view on the main thread.
Combine and Asynchronous Execution:
The Combine framework is exclusively utilized within the Process
object, which is responsible for initiating external tasks,
such as the rsync
synchronize task. Combine is employed to monitor two specific notifications.
NSNotification.Name.NSFileHandleDataAvailable
Process.didTerminateNotification
and act when they are observed. The rsync
synchronize task is completed when the last notification is observed.
// Combine, subscribe to NSNotification.Name.NSFileHandleDataAvailable
NotificationCenter.default.publisher(
for: NSNotification.Name.NSFileHandleDataAvailable)
.sink { [self] _ in
....
}.store(in: &subscriptons)
// Combine, subscribe to Process.didTerminateNotification
NotificationCenter.default.publisher(
for: Process.didTerminateNotification)
.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
.sink { [self] _ in
....
subscriptons.removeAll()
}.store(in: &subscriptons)
About changes
RsyncUI adheres to the concurrency model introduced in Swift 6. Refer to the official Swift documentation for more information:
“A data race occurs when one thread accesses memory while another thread is modifying the same memory. The Swift 6 language mode eliminates these issues by preventing data races at compile time.”
Code Refactoring and Review:
RsyncUI comprises approximately 200 Swift files and 14,700 lines of code. This includes the main repository for RsyncUI and four Swift Packages for RsyncUI. Notably, RsyncUI does not rely on external libraries; it is constructed using default Swift libraries and Swift/SwiftUI code exclusively.
While RsyncUI maintains stability, certain sections of the code may require periodic review. Refactoring is generally beneficial, enhancing code readability, efficiency, and maintainability. However, it is essential to acknowledge that refactoring may occasionally yield unexpected outcomes.
Main Repository:
RsyncUI - The primary repository for RsyncUI.
RsyncArguments - Generate parameters for
rsync
based on configurations.sshCreateKey - Assist in creating an SSH identity file and key using RsyncUI.
- Generate an RSA-based SSH key for default and user-defined keys, including the SSH port number.
DecodeEncodeGeneric - Generic code for decoding and encoding JSON data.
ParseRsyncOutput - Parse and extract numerical values from the output of
rsync
. This data is used to display details and log results for synchronized tasks.
Version 2.2.1
Version 2.2.1 (build 120) - 30 November 2024
Occasionally, refactoring can result in unintended side effects. Verifying that a refactoring does not cause any issues can be challenging. However, when such an occurrence arises, it is crucial to promptly address the issue and release a new version. The fix for this particular issue was relatively straightforward, involving a single line of code modification. Temporarily disabling the Monitor network during profile updates was implemented to resolve the problem.
The bug in question affected the Profiles view, where users create and delete profiles. When the Monitor network was enabled, RsyncUI entered an infinite loop, displaying no connection to the network.
Version 2.2.0
Version 2.2.0 (build 120) - 29 November 2024
The main new feature in this release is a view to verify if your local data needs to be updated from remote or not. If you are using two or more macs, which I do, and all macs synchronise data to the same remote storage. If that remote storage is not a Git server, like GitHub, there might be some challenges keeping the macs in sync and not losing any data.
See more info.
Other changes
- fixed a bug in discover the phrase
rsync error:
in output from rsync- discover error must be set in RsyncUI Settings, an error is thrown if RsyncUI discover any output from rsync with the above error
- fixed an issue with monitor network, networked tasks only
- the German translation is updated and proofread by Andre Voigtmann
- still a few refactors
- the number of output from rsync is increased from 10,000 to 40,000 before truncation of output
- seems like SwiftUI handles tables of 40,000 lines very well
The discover error bug
In version 2.1.6, there was a refactor to replace Combine in several places in code. Combine is only used within the Process object:
Combine is only used in the Process object
listening for signals from rsync
when it executes, as far as I understand from reading other articles about Combine it is not clear what the future of
Combine is
The refactor of Combine introduced a bug for discover rsync error:
Discover rsync error:
from
the rsync output requiere set on in RsyncUI Settings. If an error is discovered, a message is thrown and the error is
written to the log.
Monitor network
Monitor network is set on or off in RsyncUI settings.
Lately, on macOS Sequoia, the monitor network has reported some false negatives. And sometimes it does not complain about missing network at all. I dont know why this happens. There is a timout, a few seconds, on the check, and if the respond from server is not received before timeout an error is thrown.
The check verify, by TCP on port 22 if port is not changed, that the server responds. And sometimes when the code throws an error dropped network, RsyncUI still manage to pull data from the server.
The monitor network code is refactored and only checked once, if set on, when the profile is loaded and there are networked tasks.
Version 2.1.8
Version 2.1.8 (build 118) - 14 November 2024
The following are updated, and the user documentation is updated as well.
- a few refactors and fixes, most of the code are now reviewed
- the estimate view is updated, an arrow points which task is estimated, blue text indicate estimate is completed
- in Task view, there is a new view for global changes, either parts of string or full string
- in Task view, a notify to remeber update when there are changes
Version 2.1.6
Version 2.1.6 (build 116) - 29 October 2024
This release is primarly review and refactor of code where appropriate. And a few minor fixes as well. And the review of code will continue until all code is checked…
- issue with links to the Changelog and documentation are fixed
- I have tested RsyncUI on new macOS Sequoia, a virtual machine, and added some updates when there is a new install
- added a check if the selected profile contains any tasks, functions like estimate and execute are disabled until a task is added
- in Rsync parameters view, minor fix when adding your own parameters to
rsync
- it is working today, but the view itself is not properly reset after adding a parameter
There has been several refactors last two weeks, the detailed changelog show all files which are updated since previous release.
- most
for
loops are refactored using higher order functions likemap
,compactMap
, higher order functions are quicker and makes the code cleaner and easier to read - Combine is replaced where used for
debounce
function only, replaced by usingtry await Task.sleep(seconds: 1)
, seconds may be 1, 2 or 3 seconds depends on the case - Combine is only used in the Process object
listening for signals from
rsync
when it executes, as far as I understand from reading other articles about Combine it is not clear what the future of Combine is - cleaned up “trimming” of output from
rsync
used in Snapshots, Restore - and a few other refactors as well, I am reviewing most of the code
- Quicktask now remember the last task, filetransfer is also enabled in Quicktask
- its is also possible to create task for one file only, see a short workaround to make it happen
Version 2.1.5
Version 2.1.5 (build 115) - 13 October 2024
There is a minor issue in this version, the links for documentation and the changelog in RsyncUI are not updated after new theme for documentation is applied.
This is a maintenance release, some refactor of code, a few bugfixes and GUI updates. Focus in this version is to make most of functions context sensitive.
- functions, data and selections are hidden until a task is selected
- an example is within the Rsync parameters view, the checker flag for a
--dry-run
is not visible until a task is selected
- an example is within the Rsync parameters view, the checker flag for a
- refactor and cleanup of code
- fixed another bug in ssh and remote servers
- fixed a bug in Settings view
- a few minor GUI updates
Version 2.1.4
Version 2.1.4 (build 114) - 27 September 2024
The following are updates:
- disable main functions during work
- all main functions on the sidebar including change profile, are disabled when there are remote execution like synchronization, restore and so on
- this is to prevent any sideeffects when remote executions are at work
- additional cleanups in Settings view
- be aware of there are some seconds of delay when changing settings which must be verified before saving
- show command strings (in view for Rsync parameters)
- RsyncUI creates commands for external execution, almost all commands are dependent upon values in each configuration
- this view is for documentation for users who want to do a more detailed view of what RsyncUI does
- by using the Console app, see below, all major steps of what RsyncUI does might be viewed
- refactor in parts of code
- refactoring and cleanup of internal code are always in focus, there is always potential for cleanup and improvements
- there are about 146 Swift files and 10,000 lines of Swift code, there are no memory leaks, verified by the Xcode instruments tool
- see the release for details about changes
- Console and OSLog
- from Swift 5 there is a unified logging feature
OSLog
. - the OSLogs might be read by using the macOS Console app, set the Action in Console app menu to
Include Info Messages
and enterno.blogspot.RsyncUI
as subsystem within the search field
- from Swift 5 there is a unified logging feature
Version 2.1.3
Version 2.1.3 (build 113) - 16 September 2024
Sorry for many updates in a few days, but sometime a previous quick bugfix is not working as expected. Which was the case with previous release. There has been a few updates in this release. Mostly in computing arguments for ssh-parameters, applies for remote servers only. And there has also been a couple of GUI updates as well.
Next release again will probably be in a month or two, depending if no other bugs are found within this period.
Version 2.1.2 (build 112) - 13 September 2024
Fixed a bug in ssh-parameters, applies for using remote servers only.
After some more testing, using Swift Testing, I discovered a few more issues about ssh-parameters. Local set ssh-parameters rules global set ssh-parameters. Local ssh-keypath or ssh-port should only set one of them even if there are global set ssh-keypath and ssh-port.
ssh parameters in version 2.1.2 (build 112) does not work as expected. But default values for RSA based ssh-key and identityfile, ~/.ssh/id_rsa
and ssh-port = 22
, are automatically picked up by rsync
. This is a workaround until version 2.1.3 is released in some days.
There will be a new version 2.1.3 (build 113) including fixes for the above by next week, the week starting with Monday 16 September 2024. The package RsyncArguments and tests are updated.
Version 2.1.1
Updates in version 2.1.1
The work on adapting RsyncUI to the new concurrency model of Swift 6 is complete.
- RsyncUI is now fully adapted to Swifts new concurrency model and Swift version 6
- in Xcode
SWIFT_STRICT_CONCURRENCY = complete
andSWIFT_VERSION = 6;
is set
- in Xcode
- there has been several refactor of code and a few UI updates
- by using the tool periphery, the code is cleaned and all not used classes, structs, functions and attributes are deleted
- some of the code is created as packages, see comments about Swift Testing and Swift Package Manager below
- thx to Cavaliere100 for testing RsyncUI on MacOS Sequoia and experienced an application crash for new users
- RsyncUI is tested on macOS Sequoia, built by Xcode16 beta4 and it is verified working as expected
- there is a new export and import function, tasks can now be exported and imported between profiles and to new Macs
- import and export is by file
- some more info about export and import
- fixed bug if user defined path for
rsync
is not valid - restore data only valid from remote servers, restore data from local attached disc by macOS Finder only
- fixed a bug in parameters to rsync and create ssh-key, default and user define ssh-key
- fixed a bug in passwordless logins
- example of the rsync command which causes the issue is:
rsync -e ssh -r --list-only thomas@raspberrypi:/backups/Documents/
- should be
rsync --verbose --compress -e ssh -i ~/.ssh_rsyncosx/rsyncosx -p 22 -r --list-only thomas@raspberrypi:/backups/Documents/
if user defined ssh-key and identityfile are enabled
- example of the rsync command which causes the issue is:
- it is allowed to change snapshot number in snapshot tasks
- if you are changing the snapshot number be sure you now what you are doing
Xcode 16, Swift Testing and Swift Package Manager
The new version number of RsyncUI is ver 2.1.1 build 111 due to using Swift Package Manager (SPM) and Swift Testing is a significant change to increase quality of code. By using SPM, parts of the source code in RsyncUI is extraced and created as packages.
- RsyncArguments - create parameters to
rsync
from configurations - sshCreateKey - assist to create ssh identityfile and key in RsyncUI
- create RSA based ssh-key for default and user defined keys including ssh-port number
- DecodeEncodeGeneric - generic code for Decode and Encode JSON data
- ParseRsyncOutput - parse and extract numbers from output from
rsync
, used in view for details and log result of a synchronize tasks
By SPM and Swift Testing, the code for RsyncUI is modularized, isolated, and tested before committing changes.
Historic releases
Previous releases
Dates and version only
- Version 1.9.2 (build 100) - 11 June 2024
- Version 1.9.1 (build 99) - 27 May 2024
- Version 1.9.0 (build 98) - 12 April 2024
- Version 1.8.9 (build 97) - 26 March 2024
- Version 1.8.8 (build 96) - 14 March 2024
- Version 1.8.7 (build 95) - 20 February 2024
- Version 1.8.6 (build 94) - 30 January 2024
- Version 1.8.2 (build 92) - 8 January 2024
- Version 1.8.1 (build 91) - 29 December 2023
- Version 1.8.0 (build 90) - 18 December 2023
- Version 1.7.9 (build 89) - 7 December 2023
- Version 1.7.8 build (88) and 1.7.5 build (88) - 23 November 2023
- Version 1.7.3 build (86) - 19 October 2023
- Version 1.7.5 build (84) - 28 September 2023
- Version 1.7.2 build (85) - 23 September 2023
- Version 1.7.1 build(83) - 1 September 2023
- Version 1.7.0 build(82) - 16 August 2023
- Version 1.6.6 build(81) - 1 August 2023
- Version 1.6.5 build(80) - 16 July 2023
- Version 1.6.3 build(79) - 29 June 2023
- Version 1.6.1 build(77) - 20 June 2023
- Version 1.6.0 build(76) - 16 June 2023
- Version 1.5.0 build(73) - 4 May 2023
- Version 1.4.8 build(70) - 24 March 2023
- Version 1.4.7 build(69) - 14 March 2023
- Version 1.4.5 build(67) - 7 March 2023
- Version 1.4.3 build (65) - 8 February 2023
- Version 1.4.2 build (64) - 6 January 2023
- Version 1.4.0 build (62) - 6 December 2022
- Version 1.3.9 build (57) - 18 November 2022
- Version 1.3.8 build (56) release candidate - 10 November 2022
- Version 1.3.7 build (56) - 5 November 2022
- Version 1.3.6 build (55) - 31 October 2022
- Version 1.3.0 build (53) - 30 September 2022
- Version 1.2.9 build (52) - 8 September 2022
- Version 1.2.8 build (51) - 20 March 2022
- Version 1.2.7 build (50) - 17 March 2022
- Version 1.2.6 build (48) - 31 December 2021
- Version 1.2.5 build (48) - 6 December 2021
- Version 1.2.3 build (46) - 11 November 2021
- Version 1.2.2 build (45) - 28 October 2021
- Version 1.2.1 build (42) - 21 October 2021
- Version 1.2.0 build (41) - 28 September 2021
- Version 1.1.2 build (40) - 9 September 2021
- Version 1.1.2 build (39) - 1 September 2021
- Version 1.1.2 build (38) - 28 August 2021
- Version 1.1.2 build (37) - 21 August 2021
- Version 1.1.2 build (36) - 16 August 2021
- Version 1.1.2 build (35) - 11 August 2021
- Version 1.1.2 build (34) - 30 July 2021
- Version 1.1.2 build (28)
- Version 1.1.1 build (27)
- Version 1.1.0 build (26)
- Version 1.0.1 build (24)
- Version 1.0.0 build (23)
- Prerelease version 0.99 build (22)
- Prerelease v0.60 build (20) - breaking changes
- Prerelease v0.55 build (19) - 14 April 2021
- Prerelease v0.49 build (18)
- Prerelease v0.48 build (17)
- Prerelease v0.47 build (16)
- Prerelease v0.45 build (15)
- Prerelease v0.42 build (14)
- Prerelease v0.41 build (12)
- Prerelease v0.39 build (11)
- Prerelease v0.36 build (10)
- Prerelease v0.36 build (8)
- Prerelease v0.35 build (7)
- Prerelease v0.3 build (6) - 12 March 2021