├── src ├── Open Configuration.cmd ├── assets │ ├── arrow.png │ ├── logo.ico │ └── iconfinder_icon-skip-forward_211889.png ├── Classes │ ├── Utilities │ │ ├── Base │ │ │ ├── ViewModelBase.cs │ │ │ ├── DelegateCommand.cs │ │ │ └── RelayCommand.cs │ │ ├── Converters │ │ │ ├── ShowUnderscoreConverter.cs │ │ │ ├── StringCapitalizeConverter.cs │ │ │ ├── ObjectToTupleWithParameterConverter.cs │ │ │ ├── BooleanAndConverter.cs │ │ │ ├── Boolean3AndConverter.cs │ │ │ ├── InverseBooleanConverter.cs │ │ │ ├── BooleanToVisibilityConverter.cs │ │ │ ├── SuggestConvertToUserOverridedVisibilityMultiValueConverter.cs │ │ │ ├── InstallationStatusToVisibilityMultiValueConverter.cs │ │ │ └── SuggestRemoveOrConvertBackVisibilityMultiValueConverter.cs │ │ ├── ExtensionMethods.cs │ │ └── FullyObservableCollection.cs │ ├── SelfService │ │ ├── Branding.cs │ │ ├── ProxyConfigurator.cs │ │ ├── TrayIconUpdatesAreAvailable.cs │ │ ├── Startup │ │ │ ├── CommandLine.cs │ │ │ └── SchedulerCommandLineTasks.cs │ │ ├── SchedulerManager.cs │ │ ├── SelfUpdate.cs │ │ ├── Upgrade.cs │ │ └── AppDataPersistence.cs │ ├── Models │ │ └── Mockups │ │ │ └── NewVersionWindowInstallationsMockup.cs │ ├── Adoptium │ │ ├── AdoptiumHelpMessagesActions.cs │ │ ├── AdoptiumTools.cs │ │ ├── AdoptiumInstallationsDiscoverer.cs │ │ └── AdoptiumTransitionRouter.cs │ ├── Updater │ │ ├── Workers │ │ │ └── UpdateChecker.cs │ │ └── Updater.cs │ ├── Tools.cs │ └── ViewModels │ │ └── AddInstallationFromWebViewModel.cs ├── HelpHowToInstallNewWindow.xaml.cs ├── LICENSE.txt ├── Styles │ ├── CommonStyles.xaml │ ├── ConfigurationWindow.CustomStyles.xaml │ └── AdoptLogo.xaml ├── Windows │ ├── SelfUpdateDialog.xaml.cs │ ├── AddInstallationFromWebWindow.xaml.cs │ ├── SettingsWindow.xaml.cs │ └── SelfUpdateDialog.xaml ├── Settings.cs ├── packages.config ├── AJUpdateWatcher.args.json ├── NewVersionWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── app.manifest │ ├── Settings.settings │ └── Resources.resx ├── AJUpdateWatcher.sln ├── App.config ├── HelpHowToInstallNewWindow.xaml ├── App.xaml.cs ├── App.xaml └── ConfigurationWindow.xaml.cs ├── docs ├── first_run.png ├── JAVA_HOME_LTS.gif ├── adv_config_1.png ├── adv_config_2.png ├── check_on_logon.png ├── config_dialog.png ├── download_new_1.png ├── download_new_2.png ├── download_new_4.png ├── logo.128x121.png ├── logo.200x189.png ├── update_dialog.gif ├── update_dialog.png ├── v1 │ ├── first_run.png │ ├── config_dialog.png │ └── update_dialog.png ├── self-update-dialog.png ├── update_dialog_838.gif ├── config_lower_buttons.png ├── do_not_skip_any_more.gif ├── update_dialog+context.png ├── autodiscovery_settings.png ├── first_run_config_example.gif ├── do_not_skip_any_more+config.png ├── first_run_config_example_cut.gif ├── scheduler-consistency-check.png ├── settings-post-install-scripts-tab.png ├── unset_one_of_automatic_instances.gif ├── context_menu_for_autodiscovered_instance.png └── sample-scripts │ ├── get_candidates.ps1 │ └── update_junctions.ps1 ├── .github ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── dependabot.yml └── workflows │ ├── build-and-test-dotnet.yml │ └── codeql-analysis.yml ├── SECURITY.md ├── tests └── AJBasicUnitTests │ ├── Properties │ └── AssemblyInfo.cs │ └── packages.config ├── 3rdparty_licensing ├── 3RDPARTY.txt ├── MIT.txt ├── Unlicense.txt ├── FreeBSD.txt └── MS-PL.md ├── AJUpdateWatcher-PackZIP.ps1 ├── AJUpdateWatcher-list-to-ZIP.txt ├── LICENSE.txt ├── README_v1.md └── .gitignore /src/Open Configuration.cmd: -------------------------------------------------------------------------------- 1 | @start AJUpdateWatcher.exe -config -------------------------------------------------------------------------------- /docs/first_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/first_run.png -------------------------------------------------------------------------------- /src/assets/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/src/assets/arrow.png -------------------------------------------------------------------------------- /src/assets/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/src/assets/logo.ico -------------------------------------------------------------------------------- /docs/JAVA_HOME_LTS.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/JAVA_HOME_LTS.gif -------------------------------------------------------------------------------- /docs/adv_config_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/adv_config_1.png -------------------------------------------------------------------------------- /docs/adv_config_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/adv_config_2.png -------------------------------------------------------------------------------- /docs/check_on_logon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/check_on_logon.png -------------------------------------------------------------------------------- /docs/config_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/config_dialog.png -------------------------------------------------------------------------------- /docs/download_new_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/download_new_1.png -------------------------------------------------------------------------------- /docs/download_new_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/download_new_2.png -------------------------------------------------------------------------------- /docs/download_new_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/download_new_4.png -------------------------------------------------------------------------------- /docs/logo.128x121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/logo.128x121.png -------------------------------------------------------------------------------- /docs/logo.200x189.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/logo.200x189.png -------------------------------------------------------------------------------- /docs/update_dialog.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/update_dialog.gif -------------------------------------------------------------------------------- /docs/update_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/update_dialog.png -------------------------------------------------------------------------------- /docs/v1/first_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/v1/first_run.png -------------------------------------------------------------------------------- /docs/v1/config_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/v1/config_dialog.png -------------------------------------------------------------------------------- /docs/v1/update_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/v1/update_dialog.png -------------------------------------------------------------------------------- /docs/self-update-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/self-update-dialog.png -------------------------------------------------------------------------------- /docs/update_dialog_838.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/update_dialog_838.gif -------------------------------------------------------------------------------- /docs/config_lower_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/config_lower_buttons.png -------------------------------------------------------------------------------- /docs/do_not_skip_any_more.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/do_not_skip_any_more.gif -------------------------------------------------------------------------------- /docs/update_dialog+context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/update_dialog+context.png -------------------------------------------------------------------------------- /docs/autodiscovery_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/autodiscovery_settings.png -------------------------------------------------------------------------------- /docs/first_run_config_example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/first_run_config_example.gif -------------------------------------------------------------------------------- /docs/do_not_skip_any_more+config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/do_not_skip_any_more+config.png -------------------------------------------------------------------------------- /docs/first_run_config_example_cut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/first_run_config_example_cut.gif -------------------------------------------------------------------------------- /docs/scheduler-consistency-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/scheduler-consistency-check.png -------------------------------------------------------------------------------- /docs/settings-post-install-scripts-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/settings-post-install-scripts-tab.png -------------------------------------------------------------------------------- /docs/unset_one_of_automatic_instances.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/unset_one_of_automatic_instances.gif -------------------------------------------------------------------------------- /docs/context_menu_for_autodiscovered_instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/docs/context_menu_for_autodiscovered_instance.png -------------------------------------------------------------------------------- /src/assets/iconfinder_icon-skip-forward_211889.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tushev/aojdk-updatewatcher/HEAD/src/assets/iconfinder_icon-skip-forward_211889.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **I'm sure that it's not a 'known-not-a-bug'** 11 | **See**: https://github.com/tushev/aojdk-updatewatcher/wiki/Known-not-a-bugs 12 | [X] Yes 13 | 14 | ## 15 | I would like to ... 16 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Base/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace AJ_UpdateWatcher 4 | { 5 | public class ViewModelBase : INotifyPropertyChanged 6 | { 7 | public event PropertyChangedEventHandler PropertyChanged; 8 | 9 | protected void OnPropertyChanged(string propertyName) 10 | { 11 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 12 | } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | [![GitHub release](https://img.shields.io/github/release/tushev/aojdk-updatewatcher.svg)](https://GitHub.com/tushev/aojdk-updatewatcher/releases/) 6 | 7 | :white_check_mark: Only the most recent version (displayed above) is supported. 8 | 9 | ## Reporting a Vulnerability 10 | 11 | Use the following link to report a vulnerability: https://github.com/tushev/aojdk-updatewatcher/security/advisories/new 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /src/Classes/SelfService/Branding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AJ_UpdateWatcher 8 | { 9 | static public class Branding 10 | { 11 | static public readonly string MessageBoxHeader = "Update Watcher for AdoptOpenJDK / Eclipse Temurin™ / IBM® Semeru® Open Edition"; 12 | static public readonly string ProductName = "Update Watcher for AdoptOpenJDK"; 13 | static public readonly string TargetProduct = "AdoptOpenJDK / Eclipse Temurin™ / IBM® Semeru® Open Edition"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test-dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup .NET 6 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 6.0.x 20 | - name: Restore dependencies 21 | run: dotnet restore "src\AJUpdateWatcher.sln" 22 | - name: Build 23 | run: dotnet build "src\AJUpdateWatcher.sln" --no-restore 24 | - name: Test 25 | run: dotnet test --no-build --verbosity normal "src\AJUpdateWatcher.sln" 26 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/ShowUnderscoreConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace AJ_UpdateWatcher 10 | { 11 | public class ShowUnderscoreConverter : IValueConverter 12 | { 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => 14 | value is string text ? text.Replace("_", "__") : null; 15 | 16 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => 17 | value is string text ? text.Replace("__", "_") : null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/AJBasicUnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("AJBasicUnitTests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("AJBasicUnitTests")] 10 | [assembly: AssemblyCopyright("Copyright © 2020")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("5d4eb130-8d26-4c61-a301-c2a228ba09dd")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /3rdparty_licensing/3RDPARTY.txt: -------------------------------------------------------------------------------- 1 | This application contains the following 3rd party elements: 2 | 3 | * https://www.iconfinder.com/icons/211889/forward_skip_icon MIT License 4 | 5 | * System.Threading.Tasks.Dataflow.dll MIT License 6 | * zeluisping/LoadingIndicators.WPF The Unlicense 7 | * dahall/TaskScheduler MIT License 8 | * JamesNK/Newtonsoft.Json MIT License 9 | * System.ValueTuple MIT License 10 | * DotNetProjects.Extended.Wpf.Toolkit MS-PL License 11 | * Windows Community Toolkit MIT License 12 | * MSTest.TestFramework MIT License 13 | * MSTest.TestAdapter MIT License 14 | * Fluent Command Line Parser FreeBSD License -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/StringCapitalizeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace AJ_UpdateWatcher 10 | { 11 | class StringCapitalizeConverter : IValueConverter 12 | { 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | string s = (string)value; 16 | return s.ToUpper(culture); 17 | } 18 | 19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/ObjectToTupleWithParameterConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace AJ_UpdateWatcher 10 | { 11 | class ObjectToTupleWithParameterConverter : IValueConverter 12 | { 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | return new Tuple(value, parameter); 16 | } 17 | 18 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **I'm sure that it's not a 'known-not-a-bug'** 14 | **See**: https://github.com/tushev/aojdk-updatewatcher/wiki/Known-not-a-bugs 15 | [X] Yes 16 | 17 | **Describe the solution you'd like** 18 | A clear and concise description of what you want to happen. 19 | 20 | **Describe alternatives you've considered** 21 | A clear and concise description of any alternative solutions or features you've considered. 22 | 23 | **Additional context** 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /docs/sample-scripts/get_candidates.ps1: -------------------------------------------------------------------------------- 1 | $feature_branch = '8' 2 | 3 | $adopt_registry = "Registry::HKLM\Software\AdoptOpenJDK" 4 | # use the following line if you need 32-bit installations 5 | $adopt_registry_x86 = "Registry::HKLM\Software\WOW6432Node\AdoptOpenJDK" 6 | 7 | $image_types = Get-ChildItem -Path $adopt_registry 8 | foreach ($type in $image_types) { 9 | $matching_installations = Get-ChildItem -Path $type.PSPath | Where Name -Like "*\$($feature_branch)*" 10 | 11 | $c = '' 12 | foreach ($inst in $matching_installations) { 13 | $c = (Get-ItemProperty (Get-ChildItem -Path $inst.PSPath -Recurse | Where Name -Like '*\MSI*').PSPath).Path 14 | } 15 | 16 | New-Variable -Force -Name "candidate_$($type.PSChildName)" -Value $c 17 | Write-Host "The most likely $($type.PSChildName) candidate for $($feature_branch) branch is $($c)" 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/Classes/Utilities/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | public static class ExtensionMethods 11 | { 12 | public static IEnumerable AsNotNull(this IEnumerable original) 13 | { 14 | return original ?? Enumerable.Empty(); 15 | } 16 | 17 | public static int Remove( 18 | this ObservableCollection coll, Func condition) 19 | { 20 | var itemsToRemove = coll.Where(condition).ToList(); 21 | 22 | foreach (var itemToRemove in itemsToRemove) 23 | { 24 | coll.Remove(itemToRemove); 25 | } 26 | 27 | return itemsToRemove.Count; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AJUpdateWatcher-PackZIP.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -AssemblyName System.IO.Compression 2 | 3 | $archive_filename = "$(get-location)\SetupOutput\AJUpdateWatcher-2.X.X.0-no-installer-latest-x64.zip"; 4 | 5 | Remove-Item -Path $archive_filename -ErrorAction SilentlyContinue -Confirm:$false 6 | 7 | # creates empty zip file: 8 | [System.IO.Compression.ZipArchive] $arch = [System.IO.Compression.ZipFile]::Open($archive_filename,[System.IO.Compression.ZipArchiveMode]::Update) 9 | 10 | # add your files to archive 11 | foreach ($filename in Get-Content .\AJUpdateWatcher-list-to-ZIP.txt) 12 | { 13 | $file = Get-Item -Path $filename 14 | 15 | $archive_name = $file.Name 16 | if ($file.DirectoryName -like '*3rdparty_licensing') 17 | { 18 | $archive_name = $filename 19 | } 20 | 21 | [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($arch, $file.FullName, $archive_name) 22 | } 23 | 24 | $arch.Dispose() -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: It seems that I found an error 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **I'm sure that it's not a 'known-not-a-bug'** 14 | **Check** https://github.com/tushev/aojdk-updatewatcher/wiki/Known-not-a-bugs 15 | [X] Yes 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Screenshots** 28 | If applicable, add screenshots to help explain your problem. 29 | 30 | **Desktop (please complete the following information):** 31 | - App Version [e.g. 2.0.3.0] 32 | - Windows Version [e.g. Windows 10 20H2] 33 | - JDKs/JREs [e.g. Temurin 8.0.302+8.1] 34 | 35 | **Additional context** 36 | Add any other context about the problem here. 37 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/BooleanAndConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace AJ_UpdateWatcher 11 | { 12 | class BooleanAndConverter : IMultiValueConverter 13 | { 14 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | if (values.Any(x => x == DependencyProperty.UnsetValue)) 17 | return DependencyProperty.UnsetValue; 18 | 19 | bool boolValue1 = (parameter != null) ? !(bool)values[1] : (bool)values[1]; 20 | 21 | return (bool)values[0] && boolValue1; 22 | } 23 | 24 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 25 | { 26 | throw new NotImplementedException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/Boolean3AndConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace AJ_UpdateWatcher 11 | { 12 | class Boolean3AndConverter : IMultiValueConverter 13 | { 14 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | if (values.Any(x => x == DependencyProperty.UnsetValue)) 17 | return DependencyProperty.UnsetValue; 18 | 19 | bool boolValue1 = (parameter != null) ? !(bool)values[1] : (bool)values[1]; 20 | 21 | return (bool)values[0] && boolValue1 && (bool)values[2]; 22 | } 23 | 24 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 25 | { 26 | throw new NotImplementedException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/InverseBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Data; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | [ValueConversion(typeof(bool), typeof(bool))] 11 | public class InverseBooleanConverter : IValueConverter 12 | { 13 | #region IValueConverter Members 14 | 15 | public object Convert(object value, Type targetType, object parameter, 16 | System.Globalization.CultureInfo culture) 17 | { 18 | if (targetType != typeof(bool)) 19 | throw new InvalidOperationException("The target must be a boolean"); 20 | 21 | return !(bool)value; 22 | } 23 | 24 | public object ConvertBack(object value, Type targetType, object parameter, 25 | System.Globalization.CultureInfo culture) 26 | { 27 | throw new NotSupportedException(); 28 | } 29 | 30 | #endregion 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/BooleanToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace AJ_UpdateWatcher 11 | { 12 | public class BooleanToVisibilityConverter : IValueConverter 13 | { 14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | bool boolValue = (bool)value; 17 | boolValue = (parameter != null) ? !boolValue : boolValue; 18 | return boolValue ? Visibility.Visible : Visibility.Collapsed; 19 | } 20 | 21 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 22 | { 23 | bool boolValue = (Visibility)value == Visibility.Visible; 24 | boolValue = (parameter != null) ? !boolValue : boolValue; 25 | return boolValue; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/HelpHowToInstallNewWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace AJ_UpdateWatcher 16 | { 17 | /// 18 | /// Interaction logic for HelpHowToInstallNewWindow.xaml 19 | /// 20 | public partial class HelpHowToInstallNewWindow : Window 21 | { 22 | public HelpHowToInstallNewWindow() 23 | { 24 | InitializeComponent(); 25 | this.MouseLeftButtonDown += (s, e) => { this.DragMove(); }; 26 | runTargetProduct1.Text = Branding.TargetProduct; 27 | } 28 | 29 | private void CloseButton_Click(object sender, RoutedEventArgs e) 30 | { 31 | this.Close(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AJUpdateWatcher-list-to-ZIP.txt: -------------------------------------------------------------------------------- 1 | src\bin\x64\Release\AJUpdateWatcher.exe 2 | src\bin\x64\Release\Open Configuration.cmd 3 | 3rdparty_licensing\3RDPARTY.txt 4 | 3rdparty_licensing\MIT.txt 5 | 3rdparty_licensing\MS-PL.md 6 | 3rdparty_licensing\Unlicense.txt 7 | 3rdparty_licensing\FreeBSD.txt 8 | src\bin\x64\Release\ActiveDirectoryObjectPicker.dll 9 | src\bin\x64\Release\AeroWizard.dll 10 | src\bin\x64\Release\DotNetProjects.Wpf.Extended.Toolkit.dll 11 | src\bin\x64\Release\GroupControls.dll 12 | src\bin\x64\Release\LoadingIndicators.WPF.dll 13 | src\bin\x64\Release\Microsoft.Win32.TaskScheduler.dll 14 | src\bin\x64\Release\Microsoft.Win32.TaskSchedulerEditor.dll 15 | src\bin\x64\Release\Microsoft.WindowsAPICodePack.dll 16 | src\bin\x64\Release\Microsoft.WindowsAPICodePack.Shell.dll 17 | src\bin\x64\Release\Microsoft.WindowsAPICodePack.ShellExtensions.dll 18 | src\bin\x64\Release\Newtonsoft.Json.dll 19 | src\bin\x64\Release\System.Threading.Tasks.Dataflow.dll 20 | src\bin\x64\Release\System.ValueTuple.dll 21 | src\bin\x64\Release\TimeSpan2.dll 22 | src\bin\x64\Release\FluentCommandLineParser.dll -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Simon Tushev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Classes/Models/Mockups/NewVersionWindowInstallationsMockup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AJ_UpdateWatcher.Models.Mockups 9 | { 10 | public class NewVersionWindowInstallationsMockup 11 | { 12 | public ObservableCollection InstallationsToUpdate { get; set; } 13 | 14 | public NewVersionWindowInstallationsMockup() 15 | { 16 | InstallationsToUpdate.Add(new Installation() { Path = @"C:\Program Files\AdoptOpenJDK\jre-8.0.265.01-hotspot", NewVersion = new AdoptiumReleaseVersion() { ReleaseName = "1.8.0.266" } }); 17 | InstallationsToUpdate.Add(new Installation() { Path = @"C:\Program Files\AdoptOpenJDK\jdk-11.0.8.10-hotspot", NewVersion = new AdoptiumReleaseVersion() { ReleaseName = "11.1.17" } }); 18 | InstallationsToUpdate.Add(new Installation() { Path = @"C:\Program Files\AdoptOpenJDK\jre-11.0.7.10-openj9", NewVersion = new AdoptiumReleaseVersion() { ReleaseName = "11.5.18" } }); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Simon Tushev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /3rdparty_licensing/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Classes/Utilities/Base/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Input; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | class DelegateCommand : ICommand 11 | { 12 | Predicate canExecute; 13 | Action execute; 14 | public DelegateCommand(Predicate _canexecute, Action _execute) 15 | : this() 16 | { 17 | canExecute = _canexecute; 18 | execute = _execute; 19 | } 20 | public DelegateCommand() 21 | { } 22 | public bool CanExecute(object parameter) 23 | { 24 | return canExecute == null ? true : canExecute(parameter); 25 | } 26 | public event EventHandler CanExecuteChanged; 27 | public void Execute(object parameter) 28 | { 29 | execute(parameter); 30 | } 31 | public void RaiseCanExecuteChanged() 32 | { 33 | if (CanExecuteChanged != null) 34 | CanExecuteChanged(this, new EventArgs()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Styles/CommonStyles.xaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/SuggestConvertToUserOverridedVisibilityMultiValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Data; 10 | 11 | namespace AJ_UpdateWatcher 12 | { 13 | class SuggestConvertToUserOverridedVisibilityMultiValueConverter : IMultiValueConverter 14 | { 15 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | if (values.Any(x => x == DependencyProperty.UnsetValue)) 18 | return DependencyProperty.UnsetValue; 19 | 20 | bool is_autodiscovered = (bool)values[0]; 21 | bool check_for_updates_flag = (bool)values[1]; 22 | 23 | bool boolValue = (is_autodiscovered && check_for_updates_flag); 24 | 25 | return boolValue ? Visibility.Visible : Visibility.Collapsed; 26 | 27 | } 28 | 29 | 30 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 31 | { 32 | throw new NotImplementedException(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /3rdparty_licensing/Unlicense.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /src/Windows/SelfUpdateDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace AJ_UpdateWatcher.Windows 16 | { 17 | /// 18 | /// Interaction logic for SelfUpdateDialog.xaml 19 | /// 20 | public partial class SelfUpdateDialog : Window 21 | { 22 | public bool OpenReleasePageInstead = false; 23 | 24 | public SelfUpdateDialog() 25 | { 26 | InitializeComponent(); 27 | } 28 | 29 | private void btnInstall_Click(object sender, RoutedEventArgs e) 30 | { 31 | DialogResult = true; 32 | } 33 | 34 | private void btnClose_Click(object sender, RoutedEventArgs e) 35 | { 36 | DialogResult = false; 37 | } 38 | 39 | private void btnOpenRelease_Click(object sender, RoutedEventArgs e) 40 | { 41 | OpenReleasePageInstead = true; 42 | DialogResult = true; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace AJ_UpdateWatcher.Properties { 2 | 3 | 4 | // This class allows you to handle specific events on the settings class: 5 | // The SettingChanging event is raised before a setting's value is changed. 6 | // The PropertyChanged event is raised after a setting's value is changed. 7 | // The SettingsLoaded event is raised after the setting values are loaded. 8 | // The SettingsSaving event is raised before the setting values are saved. 9 | internal sealed partial class Settings { 10 | 11 | public Settings() { 12 | // // To add event handlers for saving and changing settings, uncomment the lines below: 13 | // 14 | // this.SettingChanging += this.SettingChangingEventHandler; 15 | // 16 | // this.SettingsSaving += this.SettingsSavingEventHandler; 17 | // 18 | } 19 | 20 | private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { 21 | // Add code to handle the SettingChangingEvent event here. 22 | } 23 | 24 | private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { 25 | // Add code to handle the SettingsSaving event here. 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /docs/sample-scripts/update_junctions.ps1: -------------------------------------------------------------------------------- 1 | $feature_branch = '11' 2 | $your_junction = 'c:\path\to\your-junction' 3 | 4 | $adopt_registry = "Registry::HKLM\Software\AdoptOpenJDK" 5 | # use the following line if you need 32-bit installations 6 | # $adopt_registry = "Registry::HKLM\Software\WOW6432Node\AdoptOpenJDK" 7 | 8 | $image_types = Get-ChildItem -Path $adopt_registry 9 | foreach ($type in $image_types) { 10 | $matching_installations = Get-ChildItem -Path $type.PSPath | Where Name -Like "*\$($feature_branch)*" 11 | 12 | $c = '' 13 | foreach ($inst in $matching_installations) { 14 | $c = (Get-ItemProperty (Get-ChildItem -Path $inst.PSPath -Recurse | Where Name -Like '*\MSI*').PSPath).Path 15 | } 16 | 17 | New-Variable -Force -Name "candidate_$($type.PSChildName)" -Value $c 18 | Write-Host "The most likely $($type.PSChildName) candidate for $($feature_branch) branch is $($c)" 19 | } 20 | Write-Host "(not necessary the highest version ones, just the last encountered in the registry)" 21 | Write-Host 22 | 23 | # uncomment these lines and change them as needed 24 | 25 | # Remove-Item "$($your_junction)" -Force -Confirm:$False 26 | # cmd /c mklink /j "$($your_junction)" "$($candidate_JDK)" 27 | 28 | Write-Host "THE COMMAND LOOKS LIKE: << cmd /c mklink /j ""$($your_junction)"" ""$($candidate_JDK)"" >>, please edit the source to enable it" -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/InstallationStatusToVisibilityMultiValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Data; 10 | 11 | namespace AJ_UpdateWatcher 12 | { 13 | public class InstallationStatusToVisibilityMultiValueConverter : IMultiValueConverter 14 | { 15 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | if (values.Any(x => x == DependencyProperty.UnsetValue)) 18 | return DependencyProperty.UnsetValue; 19 | 20 | bool is_autodiscovered = (bool)values[0]; 21 | bool check_for_updates_flag = (bool)values[1]; 22 | bool show_shadowed = (bool)values[2]; 23 | 24 | bool boolValue = true; 25 | if (is_autodiscovered && check_for_updates_flag == false) 26 | boolValue = show_shadowed; 27 | 28 | return boolValue ? Visibility.Visible : Visibility.Collapsed; 29 | 30 | } 31 | 32 | 33 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /3rdparty_licensing/FreeBSD.txt: -------------------------------------------------------------------------------- 1 | FreeBSD License 2 | 3 | Fluent Command Line Parser 4 | Copyright (c) 2012 - 2013, Simon Williams 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provide 8 | d that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 14 | the following disclaimer in the documentationand/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 20 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/Classes/Utilities/Converters/SuggestRemoveOrConvertBackVisibilityMultiValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace AJ_UpdateWatcher 11 | { 12 | class SuggestRemoveOrConvertBackVisibilityMultiValueConverter : IMultiValueConverter 13 | { 14 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | if (values.Any(x => x == DependencyProperty.UnsetValue)) 17 | return DependencyProperty.UnsetValue; 18 | 19 | bool is_autodiscovered = (bool)values[0]; 20 | bool overrides_autodiscovered = (bool)values[1]; 21 | //string type_text = (string)values[2]; //for debug 22 | bool negate = (parameter != null); 23 | 24 | // VISIBLE = NOT is_autodiscovered AND (overrides_autodiscovered XNOR negate) 25 | bool boolValue = (!is_autodiscovered && (overrides_autodiscovered == negate )); 26 | 27 | return boolValue ? Visibility.Visible : Visibility.Collapsed; 28 | 29 | } 30 | 31 | 32 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/AJBasicUnitTests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/AJUpdateWatcher.args.json: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 2, 3 | "Id": "ca4bd54c-a4c8-4897-a115-be5f83c6bcc5", 4 | "Items": [ 5 | { 6 | "Id": "5d2f7236-7e4f-4820-acc9-7430fdbca627", 7 | "Command": "other", 8 | "ExclusiveMode": true, 9 | "Items": [ 10 | { 11 | "Id": "9f624842-2759-48bc-a4bb-dedab1c29a40", 12 | "Command": "-deletetask" 13 | }, 14 | { 15 | "Id": "a078ed8d-a22e-4685-941e-274bde51ac1b", 16 | "Command": "-silentlydeletetask" 17 | }, 18 | { 19 | "Id": "35cc4f59-576e-4203-b4d0-0b70fbc16263", 20 | "Command": "-askdeletetask" 21 | }, 22 | { 23 | "Id": "b653f3e2-fcac-4558-8e1e-c02751b1687d", 24 | "Command": "-forcesettask" 25 | }, 26 | { 27 | "Id": "f5a59667-d357-47c5-aba5-e50da6af9593", 28 | "Command": "-settask_askifnonconsistent" 29 | }, 30 | { 31 | "Id": "1067df1f-2442-4d67-8ac1-ed0674b72854", 32 | "Command": "", 33 | "Items": [ 34 | { 35 | "Id": "aa5a4c4f-597c-4f3a-a2bc-c2625d4c293b", 36 | "Command": "/explicitcheck" 37 | }, 38 | { 39 | "Id": "07268aaf-610b-4ea9-96df-ba17d6f4d11e", 40 | "Command": "--eXplicitCHECK" 41 | }, 42 | { 43 | "Id": "5aebb9e4-f1f5-4208-88b8-3150ee544c7f", 44 | "Command": "-explicitcheck" 45 | } 46 | ] 47 | } 48 | ] 49 | }, 50 | { 51 | "Id": "1db0d6a3-f6c4-4c32-86fc-d9be025543c0", 52 | "Command": "-config" 53 | }, 54 | { 55 | "Id": "a3e89913-e6c5-4370-94b2-e4c675dd8071", 56 | "Command": "--scheduler_donotcheckconsistency" 57 | } 58 | ] 59 | } -------------------------------------------------------------------------------- /src/Classes/SelfService/ProxyConfigurator.cs: -------------------------------------------------------------------------------- 1 | using AJ_UpdateWatcher.Properties; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace AJ_UpdateWatcher 10 | { 11 | //static class ProxyConfigurator 12 | //{ 13 | // static public bool UseProxy { get { return Settings.Default.ProxyEnabled; } } 14 | 15 | // static public IWebProxy GetWebProxy 16 | // { 17 | // get 18 | // { 19 | // if (!UseProxy) 20 | // { 21 | // return null; 22 | // } 23 | // else 24 | // { 25 | // var proxyHost = Settings.Default.ProxyHostName; 26 | // var proxyPort = Settings.Default.ProxyPort; 27 | // var proxyUserName = Settings.Default.ProxyUserName; 28 | // var proxyPassword = Settings.Default.ProxyPassword; 29 | // var proxyBypassOnLocal = Settings.Default.ProxyBypassOnLocal; 30 | // var proxyUseDefaultCredentials = Settings.Default.ProxyUseDefaultCredentials; 31 | 32 | // var proxy = new WebProxy 33 | // { 34 | // Address = new Uri($"http://{proxyHost}:{proxyPort}"), 35 | // BypassProxyOnLocal = proxyBypassOnLocal, 36 | // UseDefaultCredentials = proxyUseDefaultCredentials, 37 | 38 | // // *** These creds are given to the proxy server, not the web server *** 39 | // Credentials = new NetworkCredential( 40 | // userName: proxyUserName, 41 | // password: proxyPassword) 42 | // }; 43 | 44 | // return proxy; 45 | // } 46 | // } 47 | // } 48 | //} 49 | } 50 | -------------------------------------------------------------------------------- /src/Classes/SelfService/TrayIconUpdatesAreAvailable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | static class TrayIconUpdatesAreAvailable 11 | { 12 | static private System.Windows.Forms.NotifyIcon trayIcon; 13 | 14 | static public event EventHandler UserClickedOnIconOrNotification; 15 | 16 | static public void ShowNotification(string text = "Click for more info", int delay_ms = 10000, int second_reminder_ms = 60000) 17 | { 18 | if (trayIcon == null) 19 | { 20 | trayIcon = new System.Windows.Forms.NotifyIcon(); 21 | 22 | trayIcon.Click += (s, e) => { IconClicked(e); }; 23 | trayIcon.MouseUp += (s, e) => { IconClicked(e); }; 24 | trayIcon.BalloonTipClicked += (s, e) => { IconClicked(e); }; 25 | } 26 | 27 | trayIcon.Text = Branding.ProductName; 28 | trayIcon.BalloonTipTitle = $"New {Branding.TargetProduct} versions available"; 29 | 30 | trayIcon.Visible = true; 31 | 32 | trayIcon.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location); 33 | trayIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Warning; 34 | 35 | trayIcon.BalloonTipText = text; 36 | trayIcon.ShowBalloonTip(delay_ms); 37 | } 38 | 39 | static void IconClicked(EventArgs e) 40 | { 41 | UserClickedOnIconOrNotification?.Invoke(null, e); 42 | RemoveTrayIcon(); 43 | 44 | if (UserClickedOnIconOrNotification == null) 45 | System.Windows.Application.Current.Shutdown(); 46 | } 47 | 48 | static public void RemoveTrayIcon() 49 | { 50 | if (trayIcon != null) 51 | trayIcon.Dispose(); 52 | 53 | trayIcon = null; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Windows/AddInstallationFromWebWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Shapes; 15 | 16 | namespace AJ_UpdateWatcher 17 | { 18 | /// 19 | /// Interaction logic for AddInstallationFromWebWindow.xaml 20 | /// 21 | public partial class AddInstallationFromWebWindow : Window 22 | { 23 | public AddInstallationFromWebWindow() 24 | { 25 | InitializeComponent(); 26 | 27 | if (App.ConfigurationWindowInstance != null && App.ConfigurationWindowInstance.IsLoaded) 28 | this.Owner = App.ConfigurationWindowInstance; 29 | } 30 | 31 | private void btnWhatJREJDK_Click(object sender, RoutedEventArgs e) 32 | { 33 | AdoptiumHelpMessagesActions.ShowWhatJREJDKHelp(); 34 | } 35 | 36 | private void btnWhatImpl_Click(object sender, RoutedEventArgs e) 37 | { 38 | AdoptiumHelpMessagesActions.ShowJVM_ImplementationHelp(); 39 | } 40 | 41 | private void lblLTS_MouseUp(object sender, MouseButtonEventArgs e) 42 | { 43 | AdoptiumHelpMessagesActions.ShowLTSHelp(); 44 | } 45 | 46 | private void Path_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 47 | { 48 | AdoptiumHelpMessagesActions.OpenMainWebPage(); 49 | } 50 | 51 | private void btnWhatHeap_Click(object sender, RoutedEventArgs e) 52 | { 53 | AdoptiumHelpMessagesActions.ShowHeapHelp(); 54 | } 55 | private void btnMovingToAdoptium_Click(object sender, RoutedEventArgs e) 56 | { 57 | AdoptiumHelpMessagesActions.OpenMovingWebPage(); 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Windows/SettingsWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAPICodePack.Dialogs; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Shapes; 15 | 16 | namespace AJ_UpdateWatcher 17 | { 18 | /// 19 | /// Interaction logic for SettingsWindow.xaml 20 | /// 21 | public partial class SettingsWindow : Window 22 | { 23 | public SettingsWindow() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) 29 | { 30 | Properties.Settings.Default.Save(); 31 | } 32 | 33 | private void btnChoosePostInstallCommand_Click(object sender, RoutedEventArgs e) 34 | { 35 | bool oldTopMost = this.Topmost; 36 | this.Topmost = false; 37 | 38 | using (var dialog = new Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog()) 39 | { 40 | dialog.Filters.Add(new CommonFileDialogFilter("Executable files", "*.exe; *.com; *.bat; *.cmd; *.ps1; *.vbs; *.sh; *.ps2; *.jar")); 41 | dialog.Filters.Add(new CommonFileDialogFilter("All files", "*.*")); 42 | 43 | 44 | Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogResult result = dialog.ShowDialog(); 45 | 46 | if (result == CommonFileDialogResult.Ok) 47 | { 48 | txtPostInstallCommand.Text = dialog.FileName; 49 | } 50 | } 51 | 52 | this.Topmost = oldTopMost; 53 | } 54 | 55 | private void btnOpenSampleScriptLink_Click(object sender, RoutedEventArgs e) 56 | { 57 | System.Diagnostics.Process.Start("https://github.com/tushev/aojdk-updatewatcher/wiki/Sample-postinstall-scripts"); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/NewVersionWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using AJ_UpdateWatcher.Properties; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Security.Cryptography; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Windows; 12 | using System.Windows.Controls; 13 | using System.Windows.Data; 14 | using System.Windows.Documents; 15 | using System.Windows.Input; 16 | using System.Windows.Media; 17 | using System.Windows.Media.Imaging; 18 | using System.Windows.Shapes; 19 | using System.Windows.Threading; 20 | 21 | namespace AJ_UpdateWatcher 22 | { 23 | /// 24 | /// Interaction logic for NewVersionWindow.xaml 25 | /// 26 | public partial class NewVersionWindow : Window 27 | { 28 | NewVersionViewModel NewVersionVM; 29 | 30 | public NewVersionWindow(bool invoked_from_ui = false) 31 | { 32 | InitializeComponent(); 33 | 34 | NewVersionVM = new NewVersionViewModel(invoked_from_ui); 35 | this.DataContext = NewVersionVM; 36 | 37 | HeaderArea.MouseLeftButtonDown += (s, e) => { this.DragMove(); }; 38 | } 39 | 40 | public void SetInvokedFromUIState(bool invoked_from_ui) 41 | { 42 | NewVersionVM.InvokedFromUI = invoked_from_ui; 43 | } 44 | 45 | public void RefreshUpdates() 46 | { 47 | NewVersionVM.ForceUpdateCheck(); 48 | } 49 | 50 | private void btnOpenConfig_Click(object sender, RoutedEventArgs e) 51 | { 52 | App.ShowConfigurationWindow(); 53 | } 54 | 55 | private void NewVersionWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) 56 | { 57 | NewVersionVM.SaveModel(); 58 | Settings.Default.Save(); 59 | } 60 | 61 | private void CloseButton_Click(object sender, RoutedEventArgs e) 62 | { 63 | Close(); 64 | } 65 | 66 | private void btnMovingToAdoptium_Click(object sender, RoutedEventArgs e) 67 | { 68 | AdoptiumHelpMessagesActions.OpenMovingWebPage(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Classes/Adoptium/AdoptiumHelpMessagesActions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace AJ_UpdateWatcher 10 | { 11 | static class AdoptiumHelpMessagesActions 12 | { 13 | static public void ShowJVM_ImplementationHelp() 14 | { 15 | MessageBox.Show( 16 | "HotSpot is the VM from the OpenJDK community." + Environment.NewLine + 17 | "It is the most widely used VM today and is used in Oracle’s JDK. It is suitable for all workloads." + Environment.NewLine + Environment.NewLine + 18 | "Eclipse OpenJ9 is the VM from the Eclipse community." + Environment.NewLine + 19 | "It is an enterprise-grade VM designed for low memory footprint and fast start-up and is used in IBM’s JDK. It is suitable for running all workloads.", "An advice from AdoptOpenJDK.net", MessageBoxButton.OK, MessageBoxImage.Information); 20 | } 21 | static public void ShowHeapHelp() 22 | { 23 | MessageBox.Show( 24 | @"What are the OpenJ9 ""Large Heap"" variants ?" + Environment.NewLine + Environment.NewLine + 25 | @"The Large Heap variants of the OpenJ9 builds" + Environment.NewLine + 26 | @"(also known as the ""non-compressed references builds"")" + Environment.NewLine + 27 | @"allow for Java heap sizes greater than 57Gb." + Environment.NewLine + Environment.NewLine + 28 | @"If you need heap sizes that large, then pick the large heap versions.", "An advice from AdoptOpenJDK.net/faq.html", MessageBoxButton.OK, MessageBoxImage.Information); 29 | } 30 | 31 | static public void ShowWhatJREJDKHelp() 32 | { 33 | Process.Start("https://stackoverflow.com/questions/1906445/what-is-the-difference-between-jdk-and-jre/#1906455"); 34 | } 35 | 36 | static public void ShowLTSHelp() 37 | { 38 | Process.Start("https://adoptopenjdk.net/support.html"); 39 | } 40 | 41 | static public void OpenMainWebPage() 42 | { 43 | Process.Start("https://adoptopenjdk.net/"); 44 | } 45 | static public void OpenMovingWebPage() 46 | { 47 | Process.Start("https://blog.adoptium.net/2021/04/Adoptium-to-promote-broad-range-of-compatible-OpenJDK-builds/"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Classes/Utilities/Base/RelayCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Input; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | public class RelayCommand : ICommand 11 | { 12 | private Action execute; 13 | 14 | private Predicate canExecute; 15 | 16 | private event EventHandler CanExecuteChangedInternal; 17 | 18 | public RelayCommand(Action execute) 19 | : this(execute, DefaultCanExecute) 20 | { 21 | } 22 | 23 | public RelayCommand(Action execute, Predicate canExecute) 24 | { 25 | if (execute == null) 26 | { 27 | throw new ArgumentNullException("execute"); 28 | } 29 | 30 | if (canExecute == null) 31 | { 32 | throw new ArgumentNullException("canExecute"); 33 | } 34 | 35 | this.execute = execute; 36 | this.canExecute = canExecute; 37 | } 38 | 39 | public event EventHandler CanExecuteChanged 40 | { 41 | add 42 | { 43 | CommandManager.RequerySuggested += value; 44 | this.CanExecuteChangedInternal += value; 45 | } 46 | 47 | remove 48 | { 49 | CommandManager.RequerySuggested -= value; 50 | this.CanExecuteChangedInternal -= value; 51 | } 52 | } 53 | 54 | public bool CanExecute(object parameter) 55 | { 56 | return this.canExecute != null && this.canExecute(parameter); 57 | } 58 | 59 | public void Execute(object parameter) 60 | { 61 | this.execute(parameter); 62 | } 63 | 64 | public void OnCanExecuteChanged() 65 | { 66 | EventHandler handler = this.CanExecuteChangedInternal; 67 | if (handler != null) 68 | { 69 | //DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty)); 70 | handler.Invoke(this, EventArgs.Empty); 71 | } 72 | } 73 | 74 | public void Destroy() 75 | { 76 | this.canExecute = _ => false; 77 | this.execute = _ => { return; }; 78 | } 79 | 80 | private static bool DefaultCanExecute(object parameter) 81 | { 82 | return true; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /3rdparty_licensing/MS-PL.md: -------------------------------------------------------------------------------- 1 | # Microsoft Public License (Ms-PL) 2 | 3 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 4 | 5 | ## 1. Definitions 6 | 7 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. 8 | 9 | A "contribution" is the original software, or any additions or changes to the software. 10 | 11 | A "contributor" is any person that distributes its contribution under this license. 12 | 13 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 14 | 15 | ## 2. Grant of Rights 16 | 17 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 18 | 19 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 20 | 21 | ## 3. Conditions and Limitations 22 | 23 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 24 | 25 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 26 | 27 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 28 | 29 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 30 | 31 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 32 | -------------------------------------------------------------------------------- /src/Styles/ConfigurationWindow.CustomStyles.xaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 29 | 30 | 50 | 51 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/Classes/Adoptium/AdoptiumTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AJ_UpdateWatcher 8 | { 9 | class AdoptiumTools 10 | { 11 | static public string GetTypeOrEditionString(string id) 12 | { 13 | switch (id) 14 | { 15 | case "Eclipse Adoptium": 16 | case "Eclipse Temurin": 17 | case "Eclipse Foundation": 18 | case "Temurin": 19 | case "Adoptium": 20 | return "Eclipse Temurin™"; 21 | case "AdoptOpenJDK": 22 | return "AdoptOpenJDK"; 23 | case "SemeruOpen": 24 | return "IBM® Semeru® Open Edition"; 25 | default: 26 | return "Unknown"; 27 | } 28 | 29 | } 30 | 31 | static public string GetTypeOrEditionFromAdoptiumReleaseVersion(AdoptiumReleaseVersion version) 32 | { 33 | if ( 34 | (version.ImplementorRAW ?? "").IndexOf("Temurin", StringComparison.OrdinalIgnoreCase) >= 0 || 35 | (version.ImplementorRAW ?? "").IndexOf("Eclipse Foundation", StringComparison.OrdinalIgnoreCase) >= 0 || 36 | (version.ImplementorVersionRAW ?? "").IndexOf("Temurin", StringComparison.OrdinalIgnoreCase) >= 0 || 37 | (version.ImplementorRAW ?? "").IndexOf("adoptium", StringComparison.OrdinalIgnoreCase) >= 0 38 | ) 39 | { 40 | return "Temurin"; 41 | } 42 | else if ( 43 | (version.ImplementorRAW ?? "").IndexOf("AdoptOpenJDK", StringComparison.OrdinalIgnoreCase) >= 0 || 44 | (version.ImplementorVersionRAW ?? "").IndexOf("AdoptOpenJDK", StringComparison.OrdinalIgnoreCase) >= 0 45 | ) 46 | { 47 | return "AdoptOpenJDK"; 48 | } 49 | else if ( 50 | (version.ImplementorRAW ?? "").IndexOf("International Business Machines Corporation", StringComparison.OrdinalIgnoreCase) >= 0 || 51 | (version.ImplementorVersionRAW ?? "").IndexOf("International Business Machines Corporation", StringComparison.OrdinalIgnoreCase) >= 0 || 52 | (version.ImplementorRAW ?? "").IndexOf("IBM", StringComparison.OrdinalIgnoreCase) >= 0 || 53 | (version.ImplementorVersionRAW ?? "").IndexOf("IBM", StringComparison.OrdinalIgnoreCase) >= 0 54 | ) 55 | { 56 | return "SemeruOpen"; 57 | } 58 | else 59 | { 60 | return ""; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '31 5 * * 3' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: windows-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'csharp' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # - name: Setup .NET 6 41 | # uses: actions/setup-dotnet@v1 42 | # with: 43 | # dotnet-version: 6.0.x 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v1 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | - name: Autobuild 58 | uses: github/codeql-action/autobuild@v1 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 https://git.io/JvXDl 62 | 63 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 64 | # and modify them (or add more) to build your code if your project 65 | # uses a compiled language 66 | 67 | #- run: | 68 | # make bootstrap 69 | # make release 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v1 73 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Update Watcher for AdoptOpenJDK")] 11 | [assembly: AssemblyDescription("Independent automatic update tool for AdoptOpenJDK releases. Provided 'as is', without warranty of any kind. Use at your own risk.")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("tushev.org")] 14 | [assembly: AssemblyProduct("Update Watcher for AdoptOpenJDK")] 15 | [assembly: AssemblyCopyright("Copyright © Simon A. Tushev, 2020-2023")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("2.0.5.0")] 55 | [assembly: AssemblyFileVersion("2.0.5.0")] 56 | -------------------------------------------------------------------------------- /src/Classes/SelfService/Startup/CommandLine.cs: -------------------------------------------------------------------------------- 1 | using Fclp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | public class CommandLineOpts 11 | { 12 | public bool _Success { get; set; } 13 | public bool OpenConfigurationWindow { get; set; } 14 | public bool DeleteTask { get; set; } 15 | public bool AskDeleteTask { get; set; } 16 | public bool SilentlyDeleteTask { get; set; } 17 | public bool ForceSetTask { get; set; } 18 | public bool SetTaskAskIfNonConsistent { get; set; } 19 | public bool RunExplicitCheckForUpdates { get; set; } 20 | public bool SchedulerDoNotCheckConsistency { get; set; } 21 | 22 | internal void EnforceConsistency() 23 | { 24 | SchedulerCommandLineTasks.EnforceConsistency(this); 25 | } 26 | } 27 | 28 | static class CommandLine 29 | { 30 | public static CommandLineOpts Parse(string[] Args) 31 | { 32 | var p = new FluentCommandLineParser { IsCaseSensitive = false }; 33 | 34 | Args = ConvertArgsToConvention(Args); 35 | 36 | p.Setup(a => a.OpenConfigurationWindow).As("config").SetDefault(false); 37 | p.Setup(a => a.DeleteTask).As("deletetask").SetDefault(false); 38 | p.Setup(a => a.AskDeleteTask).As("askdeletetask").SetDefault(false); 39 | p.Setup(a => a.SilentlyDeleteTask).As("silentlydeletetask").SetDefault(false); 40 | p.Setup(a => a.ForceSetTask).As("forcesettask").SetDefault(false); 41 | p.Setup(a => a.SetTaskAskIfNonConsistent).As("settask_askifnonconsistent").SetDefault(false); 42 | p.Setup(a => a.RunExplicitCheckForUpdates).As("explicitcheck").SetDefault(false); 43 | p.Setup(a => a.SchedulerDoNotCheckConsistency).As("scheduler_donotcheckconsistency").SetDefault(false); 44 | 45 | var res = p.Parse(Args); 46 | 47 | var opts = p.Object; 48 | opts._Success = !res.HasErrors; 49 | 50 | opts.EnforceConsistency(); 51 | 52 | return opts; 53 | } 54 | 55 | private static string[] ConvertArgsToConvention(string[] Args) 56 | { 57 | string[] old_params = { 58 | "-config", 59 | "-deletetask", 60 | "-askdeletetask", 61 | "-silentlydeletetask", 62 | "-forcesettask", 63 | "-settask_askifnonconsistent", 64 | "-explicitcheck", 65 | }; 66 | 67 | var converted_args = Args.Select(arg => 68 | old_params.Contains(arg) ? 69 | $"-{arg}" : arg 70 | ).ToArray(); 71 | 72 | return converted_args; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace AJ_UpdateWatcher.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AJ_UpdateWatcher.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Classes/Adoptium/AdoptiumInstallationsDiscoverer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | public class DiscoveredInstallation 11 | { 12 | public string Path; 13 | public string Version; 14 | public string JVM_Implementation; 15 | public string ImageType; 16 | public string LastElement; 17 | public bool x64; 18 | } 19 | static class AdoptiumInstallationsDiscoverer 20 | { 21 | static string[] RegistryRoots = { @"SOFTWARE\AdoptOpenJDK", @"SOFTWARE\Eclipse Foundation", @"SOFTWARE\Eclipse Adoptium", @"SOFTWARE\Temurin", @"SOFTWARE\Semeru" }; 22 | 23 | public static List DiscoverInstallationsByRegistryHKLM() { return DiscoverInstallationsByRegistry(RegistryHive.LocalMachine); } 24 | public static List DiscoverInstallationsByRegistryHKCU() { return DiscoverInstallationsByRegistry(RegistryHive.CurrentUser); } 25 | public static List DiscoverInstallationsByRegistry(RegistryHive hive) 26 | { 27 | List paths = new List(); 28 | 29 | var RegistryViews = new List { RegistryView.Registry32, RegistryView.Registry64 }; 30 | 31 | foreach (string AdoptiumRegistryRoot in RegistryRoots) 32 | { 33 | foreach (var view in RegistryViews) 34 | { 35 | var key = RegistryKey.OpenBaseKey(hive, view); 36 | var level0key = key.OpenSubKey(AdoptiumRegistryRoot); 37 | if (level0key != null) 38 | foreach (var image in level0key.GetSubKeyNames().AsNotNull()) 39 | foreach (var version in key.OpenSubKey(AdoptiumRegistryRoot + $@"\{image}").GetSubKeyNames().AsNotNull()) 40 | foreach (var JVM in key.OpenSubKey(AdoptiumRegistryRoot + $@"\{image}\{version}").GetSubKeyNames().AsNotNull()) 41 | foreach (var last_el in key.OpenSubKey(AdoptiumRegistryRoot + $@"\{image}\{version}\{JVM}").GetSubKeyNames().AsNotNull()) 42 | { 43 | var path = key.OpenSubKey(AdoptiumRegistryRoot + $@"\{image}\{version}\{JVM}\{last_el}").GetValue("Path"); 44 | if (path != null) 45 | if ((string)path != "") 46 | paths.Add(new DiscoveredInstallation() 47 | { 48 | Path = (string)path, 49 | Version = version, 50 | JVM_Implementation = JVM, 51 | ImageType = image, 52 | LastElement = last_el, 53 | x64 = view == RegistryView.Registry64 54 | }); ; 55 | } 56 | } 57 | } 58 | return paths; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Properties/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 55 | 56 | 70 | -------------------------------------------------------------------------------- /src/Classes/Adoptium/AdoptiumTransitionRouter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace AJ_UpdateWatcher 8 | { 9 | public class AdoptiumTransitionRouter 10 | { 11 | static public bool IsMSIRevisionOnlyUpdate(AdoptiumReleaseVersion a, AdoptiumReleaseVersion b) 12 | { 13 | return 14 | a.Major == b.Major && 15 | a.Minor == b.Minor && 16 | a.Security == b.Security/* && 17 | a.MSIRevision != b.MSIRevision*/ 18 | ; 19 | } 20 | static public bool IsAdoptOpenJDK(AdoptiumReleaseVersion a) 21 | { 22 | return a.TypeOrEdition == "AdoptOpenJDK"; 23 | } 24 | static public Tuple SuggestDisabling(Installation i, AdoptiumReleaseVersion just_installed) 25 | { 26 | string text = ""; 27 | 28 | AdoptiumReleaseVersion previously_installed = i.InstalledVersion; 29 | var old_file = Path.Combine(previously_installed.LocalPath, "release"); 30 | 31 | bool reason_old_autodis_stillpresent = i.IsAutodiscoveredInstance && File.Exists(old_file); 32 | if (reason_old_autodis_stillpresent) 33 | text += $"* The old (auto-discovered) installation still seems to be present on the drive: {old_file};" + Environment.NewLine; 34 | 35 | bool reason_old_manual_not_updated = !i.IsAutodiscoveredInstance && File.Exists(old_file); 36 | if (reason_old_manual_not_updated) 37 | { 38 | var u = new Installation(i.Path); 39 | if (u.Detected) 40 | { 41 | if (just_installed > u.InstalledVersion) 42 | { 43 | text += $"* The old (manually-added) installation still seems to be present on the drive: version = {u.InstalledVersion.ParsedVersionString}, path = {u.Path}. " + Environment.NewLine; 44 | text += $"Most likely, the new installation was installed to somewhere else." + Environment.NewLine; 45 | } 46 | else 47 | reason_old_manual_not_updated = false; 48 | } else 49 | { 50 | text += $"* The old (manually-added) installation cannot be detected (A VERY RARE CASE, PLEASE MAKE A SCREENSHOT AND CONTACT THE DEVELOPER), but its release file still seems to be present on the drive: {old_file};" + Environment.NewLine; 51 | } 52 | } 53 | 54 | bool reason_msi_minor = IsMSIRevisionOnlyUpdate(previously_installed, just_installed) && File.Exists(old_file); 55 | if (reason_msi_minor) 56 | text += $"* This is a MSI 'Minor' update: most likely, Windows Installer was unable to uninstall previous version;" + Environment.NewLine; 57 | 58 | bool reason_vendor_changed = IsAdoptOpenJDK(previously_installed) && !IsAdoptOpenJDK(just_installed) && File.Exists(old_file); 59 | if (reason_vendor_changed) 60 | text += $"* Vendor change: the new build is produced by [{just_installed.ImplementorRAW.ToUpperInvariant()}], while the installed build is produced by [AdoptOpenJDK]. The old installation still seems to be present on the drive;" + Environment.NewLine; 61 | 62 | //bool reason_old_file_exists = File.Exists(old_file) && i.IsAutodiscoveredInstance; 63 | //if (reason_old_file_exists) 64 | // text += $"* Old installation seems not to be uninstalled: {old_file} still exists" + Environment.NewLine; 65 | 66 | //if is_eol disable_updates = true; ??? 67 | 68 | bool result = reason_old_autodis_stillpresent || reason_old_manual_not_updated || reason_msi_minor || reason_vendor_changed /*|| reason_old_file_exists*/; 69 | 70 | return new Tuple(result, text); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/AJUpdateWatcher.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30104.148 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AJUpdateWatcher", "AJUpdateWatcher.csproj", "{CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AJBasicUnitTests", "..\tests\AJBasicUnitTests\AJBasicUnitTests.csproj", "{5D4EB130-8D26-4C61-A301-C2A228BA09DD}" 9 | EndProject 10 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "AJInstaller-WiX", "..\installer-src\AJInstaller-WiX\AJInstaller-WiX.wixproj", "{81EB4CB2-8B40-4074-B128-AF050DD4ACFE}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Debug|x64.ActiveCfg = Debug|x64 25 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Debug|x64.Build.0 = Debug|x64 26 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Debug|x86.ActiveCfg = Debug|Any CPU 27 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Debug|x86.Build.0 = Debug|Any CPU 28 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Release|x64.ActiveCfg = Release|x64 31 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Release|x64.Build.0 = Release|x64 32 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Release|x86.ActiveCfg = Release|Any CPU 33 | {CA4BD54C-A4C8-4897-A115-BE5F83C6BCC5}.Release|x86.Build.0 = Release|Any CPU 34 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Debug|x64.ActiveCfg = Debug|Any CPU 37 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Debug|x86.ActiveCfg = Debug|Any CPU 38 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Debug|x86.Build.0 = Debug|Any CPU 39 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Release|x64.ActiveCfg = Release|x64 42 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Release|x64.Build.0 = Release|x64 43 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Release|x86.ActiveCfg = Release|Any CPU 44 | {5D4EB130-8D26-4C61-A301-C2A228BA09DD}.Release|x86.Build.0 = Release|Any CPU 45 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Debug|Any CPU.ActiveCfg = Debug|x86 46 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Debug|x64.ActiveCfg = Debug|x64 47 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Debug|x64.Build.0 = Debug|x64 48 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Debug|x86.ActiveCfg = Debug|x86 49 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Debug|x86.Build.0 = Debug|x86 50 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Release|Any CPU.ActiveCfg = Release|x64 51 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Release|Any CPU.Build.0 = Release|x64 52 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Release|x64.ActiveCfg = Release|x64 53 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Release|x64.Build.0 = Release|x64 54 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Release|x86.ActiveCfg = Release|x86 55 | {81EB4CB2-8B40-4074-B128-AF050DD4ACFE}.Release|x86.Build.0 = Release|x86 56 | EndGlobalSection 57 | GlobalSection(SolutionProperties) = preSolution 58 | HideSolutionNode = FALSE 59 | EndGlobalSection 60 | GlobalSection(ExtensibilityGlobals) = postSolution 61 | SolutionGuid = {3FF62E4C-1371-4244-9DD8-1D12C9A876A0} 62 | EndGlobalSection 63 | EndGlobal 64 | -------------------------------------------------------------------------------- /src/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | False 7 | 8 | 9 | False 10 | 11 | 12 | True 13 | 14 | 15 | https://api.github.com/repos/tushev/aojdk-updatewatcher/releases/latest 16 | 17 | 18 | 2.0.3.0 19 | 20 | 21 | False 22 | 23 | 24 | 2 25 | 26 | 27 | 0 28 | 29 | 30 | 10 31 | 32 | 33 | True 34 | 35 | 36 | True 37 | 38 | 39 | 40 | 41 | 42 | False 43 | 44 | 45 | False 46 | 47 | 48 | False 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | False 73 | 74 | 75 | -------------------------------------------------------------------------------- /README_v1.md: -------------------------------------------------------------------------------- 1 | # AdoptOpenJDK Update Watcher 2 | Automatic update tool for AdoptOpenJDK releases 3 | ![Update Dialog](/docs/v1/update_dialog.png?raw=true) 4 | ![Config Dialog](/docs/v1/config_dialog.png?raw=true) 5 | 6 | When this app launches, it gets version from **'release'** file in your local installation of OpenJDK. 7 | Then it queries AdoptOpenJDK API to check if there is a version newer than yours. 8 | If there is, you will be notified. Otherwise app quits without showing any windows or alerts. 9 | 10 | Configuration window will appear only on first run or if something goes wrong or you have explicitly called it by the corresponding shortcut. 11 | 12 | This app is best designed to run on Windows startup. I recommend to turn on **Check for AdoptOpenJDK updates on Logon** setting in configuration. If you want another schedule, turn this on and press Edit task to configure it as desired. 13 | 14 | 15 | ## Requirements 16 | Ironically, this tool is written in C# + WPF, because I am not a Java developer xD 17 | * Windows 10 _(earlier versions are likely to work as well, but I did not test that)_ 18 | * .NET Framework 4.7.2 _(the installer will do it for you)_ 19 | 20 | ## Download 21 | [Latest release](https://github.com/tushev/aojdk-updatewatcher/releases) 22 | 23 | There's a built-in update mechanism. 24 | 25 | ## Installation & configuration 26 | * Run the downloaded installer 27 | * Run the app _(make sure you are connected to the internet)_ 28 | * Set the location where the app will be looking for JDK/JRE. This may be **JAVA_HOME** environment variable _(queried at the time of check for an update)_ or a pre-defined directory 29 | * Set **Release**, **JVM Implementation** and **JVM Image type**. If not sure, read provided hints or use default values. 30 | * It is recommended to turn on **Check for AdoptOpenJDK updates on Logon**. _(If you want another schedule, turn this on and press Edit task to configure it as desired)._ 31 | ![First Run](/docs/v1/first_run.png?raw=true) 32 | * If you don't have JDK/JRE installed, click on **Open 'new version available' dialog** and the app will download and install it for you. 33 | * I recommend turning on _JAVA_HOME feature_ during setup. 34 | 35 | 36 | ## Philosophy 37 | * This app is silent during backround checks. If there is a problem connecting to the internet or AdoptOpenJDK API does not respond, it will be silent. There's nothing more annoyuing than suddenly rising error messages from nowhere. 38 | * However, it will not be silent in UI. 39 | * There are some Easter Eggs in UI. 40 | * I'm not going to actively develop this app, it's mostly 'fire-and-forget' thing. However, some functionality may be added in future, there's a built-in update mechanism. 41 | 42 | ## Disclaimer 43 | The author does not provide any support related to AdoptOpenJDK or OpenJDK. 44 | For support, please visit their corresponding websites. 45 | 46 | The author is not affiliated with or endorsed by AdoptOpenJDK or OpenJDK projects. 47 | 'AdoptOpenJDK' part of the name is used on fair use conditions, as this app works with AdoptOpenJDK releases. 48 | 49 | **THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,** 50 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 51 | 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. 52 | 53 | ## License: MIT 54 | 55 | ## Codestyle 56 | Please don't judge my coding style by this project, as I developed this app in less than a working day. It just works :) 57 | 58 | 59 | ## Known not-a-bugs 60 | * JAVA_HOME value is updated when the app is launched. If you changed its value while running configuration screen, the value will not be updated in the app. However, you can close the configuration window safely: when the next backround check occurs, actual value of JAVA_HOME at that time will be used 61 | * If the configuration app **continiously** reminds you to turn on scheduled task, this happens because you have not specified your local installation of JDK/JRE and *Release*, *JVM Implementation* and *JVM Image* to watch for. Once you set these, the app will consider itself as 'configured' and will remember your choice. 62 | -------------------------------------------------------------------------------- /src/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | False 15 | 16 | 17 | False 18 | 19 | 20 | True 21 | 22 | 23 | https://api.github.com/repos/tushev/aojdk-updatewatcher/releases/latest 24 | 25 | 26 | 2.0.3.0 27 | 28 | 29 | False 30 | 31 | 33 | 2 34 | 35 | 37 | 0 38 | 39 | 41 | 10 42 | 43 | 45 | True 46 | 47 | 48 | True 49 | 50 | 51 | 52 | 53 | 55 | False 56 | 57 | 58 | False 59 | 60 | 61 | False 62 | 63 | 84 | 85 | False 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/Classes/Utilities/FullyObservableCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Collections.Specialized; 5 | using System.ComponentModel; 6 | 7 | namespace AJ_UpdateWatcher 8 | { 9 | public class FullyObservableCollection : ObservableCollection 10 | where T : INotifyPropertyChanged 11 | { 12 | /// 13 | /// Occurs when a property is changed within an item. 14 | /// 15 | public event EventHandler ItemPropertyChanged; 16 | 17 | public FullyObservableCollection() : base() 18 | { } 19 | 20 | public FullyObservableCollection(List list) : base(list) 21 | { 22 | ObserveAll(); 23 | } 24 | 25 | public FullyObservableCollection(IEnumerable enumerable) : base(enumerable) 26 | { 27 | ObserveAll(); 28 | } 29 | 30 | protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 31 | { 32 | if (e.Action == NotifyCollectionChangedAction.Remove || 33 | e.Action == NotifyCollectionChangedAction.Replace) 34 | { 35 | foreach (T item in e.OldItems) 36 | item.PropertyChanged -= ChildPropertyChanged; 37 | } 38 | 39 | if (e.Action == NotifyCollectionChangedAction.Add || 40 | e.Action == NotifyCollectionChangedAction.Replace) 41 | { 42 | foreach (T item in e.NewItems) 43 | item.PropertyChanged += ChildPropertyChanged; 44 | } 45 | 46 | base.OnCollectionChanged(e); 47 | } 48 | 49 | protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e) 50 | { 51 | ItemPropertyChanged?.Invoke(this, e); 52 | } 53 | 54 | protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e) 55 | { 56 | OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e)); 57 | } 58 | 59 | protected override void ClearItems() 60 | { 61 | foreach (T item in Items) 62 | item.PropertyChanged -= ChildPropertyChanged; 63 | 64 | base.ClearItems(); 65 | } 66 | 67 | private void ObserveAll() 68 | { 69 | foreach (T item in Items) 70 | item.PropertyChanged += ChildPropertyChanged; 71 | } 72 | 73 | private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) 74 | { 75 | T typedSender = (T)sender; 76 | int i = Items.IndexOf(typedSender); 77 | 78 | if (i < 0) 79 | throw new ArgumentException("Received property notification from item not in collection"); 80 | 81 | OnItemPropertyChanged(i, e); 82 | } 83 | } 84 | 85 | /// 86 | /// Provides data for the event. 87 | /// 88 | public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs 89 | { 90 | /// 91 | /// Gets the index in the collection for which the property change has occurred. 92 | /// 93 | /// 94 | /// Index in parent collection. 95 | /// 96 | public int CollectionIndex { get; } 97 | 98 | /// 99 | /// Initializes a new instance of the class. 100 | /// 101 | /// The index in the collection of changed item. 102 | /// The name of the property that changed. 103 | public ItemPropertyChangedEventArgs(int index, string name) : base(name) 104 | { 105 | CollectionIndex = index; 106 | } 107 | 108 | /// 109 | /// Initializes a new instance of the class. 110 | /// 111 | /// The index. 112 | /// The instance containing the event data. 113 | public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName) 114 | { } 115 | } 116 | } -------------------------------------------------------------------------------- /src/Classes/SelfService/Startup/SchedulerCommandLineTasks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | static class SchedulerCommandLineTasks 11 | { 12 | public static bool HasSingleTask 13 | { 14 | get 15 | { 16 | return HasDeleteTaskOption || HasSetTaskOption; 17 | } 18 | } 19 | 20 | private static bool HasDeleteTaskOption { get { return CheckHasDeleteTaskOption(App.CommandLineOptions); } } 21 | private static bool CheckHasDeleteTaskOption(CommandLineOpts o) 22 | { 23 | return o.AskDeleteTask 24 | || o.DeleteTask 25 | || o.SilentlyDeleteTask; 26 | } 27 | private static bool HasSetTaskOption { get { return CheckHasSetTaskOption(App.CommandLineOptions); } } 28 | private static bool CheckHasSetTaskOption(CommandLineOpts o) 29 | { 30 | return o.ForceSetTask 31 | || o.SetTaskAskIfNonConsistent; 32 | } 33 | 34 | internal static void EnforceConsistency(CommandLineOpts o) 35 | { 36 | if (CheckHasDeleteTaskOption(o)) 37 | { 38 | o.ForceSetTask = false; 39 | o.SetTaskAskIfNonConsistent = false; 40 | } 41 | 42 | if (o.AskDeleteTask) 43 | { 44 | o.DeleteTask = false; 45 | o.SilentlyDeleteTask = false; 46 | } 47 | else 48 | { 49 | if (o.DeleteTask) 50 | { 51 | o.AskDeleteTask = false; 52 | o.SilentlyDeleteTask = false; 53 | } 54 | else 55 | { 56 | if (o.SilentlyDeleteTask) 57 | { 58 | o.AskDeleteTask = false; 59 | o.DeleteTask = false; 60 | } 61 | } 62 | } 63 | 64 | if (o.ForceSetTask) 65 | { 66 | o.SetTaskAskIfNonConsistent = false; 67 | } 68 | else 69 | { 70 | if (o.SetTaskAskIfNonConsistent) 71 | { 72 | o.ForceSetTask = false; 73 | } 74 | } 75 | } 76 | 77 | static public void ProcessSingleTask() 78 | { 79 | if (HasDeleteTaskOption) 80 | { 81 | SchedulerManager sm = new SchedulerManager(); 82 | if (sm.TaskIsSet()) 83 | { 84 | var result = App.CommandLineOptions.AskDeleteTask ? 85 | MessageBox.Show($"You have a scheduled task to check for updates of {Branding.TargetProduct}.{Environment.NewLine + Environment.NewLine}Do you want to remove this scheduled task?", Branding.MessageBoxHeader, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes) : 86 | MessageBoxResult.Yes; 87 | 88 | if (result == MessageBoxResult.Yes) 89 | { 90 | sm.DeleteTask(); 91 | 92 | if (!App.CommandLineOptions.SilentlyDeleteTask) 93 | { 94 | MessageBox.Show("Scheduled task has been removed successfully", Branding.MessageBoxHeader, MessageBoxButton.OK, MessageBoxImage.Information); 95 | } 96 | } 97 | } 98 | } 99 | 100 | if (HasSetTaskOption) 101 | { 102 | SchedulerManager sm = new SchedulerManager(); 103 | 104 | // re-create the task without asking 105 | if (App.CommandLineOptions.ForceSetTask) 106 | sm.ForceReInstallTask(); 107 | 108 | // ask if task is present and not-consistent, otherwise create it silently 109 | if (App.CommandLineOptions.SetTaskAskIfNonConsistent) 110 | { 111 | if (sm.TaskIsSet()) 112 | sm.CheckConsistency(); 113 | else 114 | sm.ForceReInstallTask(); 115 | } 116 | } 117 | 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/HelpHowToInstallNewWindow.xaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 30 | 31 | 41 | 49 | 96 | 97 | -------------------------------------------------------------------------------- /src/Classes/Updater/Workers/UpdateChecker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | 10 | namespace AJ_UpdateWatcher 11 | { 12 | public class UpdateChecker 13 | { 14 | private bool there_are_new_versions; 15 | private bool errors_occured; 16 | 17 | public List ErrorsEncountered; 18 | 19 | public EventHandler CheckComplete; 20 | public EventHandler ThereAreNewVersions; 21 | public EventHandler NoNewVersions; 22 | public EventHandler ErrorsOccuredWhileChecking; 23 | 24 | public UpdateChecker() 25 | { 26 | ResetFlags(); 27 | } 28 | 29 | private void ResetFlags() 30 | { 31 | ErrorsEncountered = new List(); 32 | 33 | there_are_new_versions = false; 34 | errors_occured = false; 35 | } 36 | 37 | public void CheckAsync(Machine machine, bool force = false) 38 | { 39 | ResetFlags(); 40 | BackgroundWorker worker = new BackgroundWorker(); 41 | 42 | worker.WorkerReportsProgress = false; 43 | there_are_new_versions = false; 44 | 45 | worker.DoWork += (s, e) => 46 | { 47 | try 48 | { 49 | var watch = System.Diagnostics.Stopwatch.StartNew(); 50 | 51 | foreach (Installation i in machine.Installations) 52 | { 53 | if (!i.CheckForUpdatesFlag || i.UpdateInProgress) 54 | continue; 55 | 56 | i.NewVersion = null; 57 | 58 | var release = i.WatchedRelease; 59 | 60 | // check for verbs 61 | if (release == AdoptiumAPI_MostRecentVerbs.MostRecentVerb) 62 | release = App.AvailableReleases.MostRecentFeatureRelease; 63 | else if (release == AdoptiumAPI_MostRecentVerbs.MostRecentLTSVerb) 64 | release = App.AvailableReleases.MostRecentLTSRelease; 65 | 66 | Debug.WriteLine($"Checking for updates for {i.Path}"); 67 | string error_message = ""; 68 | var api_version = AdoptiumAPI.GetLatestVersion(release, i.JVM_Implementation, i.ImageType, i.HeapSize, out error_message, i.Arch, i.OS); 69 | if (api_version.Found) 70 | { 71 | Debug.WriteLine($"API: {api_version.ReleaseName}"); 72 | if (api_version.ReleaseName != i.SkippedReleaseName || force) 73 | if (api_version > i.InstalledVersion || force) 74 | { 75 | Debug.WriteLine($"[API]{api_version.VersionString} > [Local]{i.InstalledVersion.VersionString}"); 76 | 77 | i.NewVersion = api_version; 78 | i.MarkedForUpdate = api_version.ReleaseName != i.SkippedReleaseName; // don't mark if skipped 79 | 80 | // reset skipped release btw 81 | if (api_version.ReleaseName != i.SkippedReleaseName && api_version > i.InstalledVersion) 82 | i.SkippedReleaseName = null; 83 | 84 | there_are_new_versions = true; 85 | } 86 | } 87 | else 88 | { 89 | errors_occured = true; 90 | string name = (i.NotInstalled ? $"New installation " : $"[{i.InstalledVersionString}]@[{i.Path}]") 91 | + $"[{ i.WatchedRelease}/{ i.ImageType}/{ i.JVM_Implementation}/{ i.HeapSize}/{ i.Arch}/{ i.OS}]"; 92 | string message = $"{name} => New Version not found: {error_message}"; 93 | ErrorsEncountered.Add(message); 94 | Debug.WriteLine($"API: Not found: {message}"); 95 | } 96 | } 97 | 98 | watch.Stop(); 99 | Debug.WriteLine($"All {machine.Installations.Count} installations checked in {watch.ElapsedMilliseconds} ms."); 100 | } 101 | catch (Exception ex) 102 | { 103 | errors_occured = true; 104 | ErrorsEncountered.Add(ex.Message); 105 | 106 | //if (force) 107 | // MessageBox.Show($"There was an error: [{ex.Message}].", Branding.MessageBoxHeader, MessageBoxButton.OK, MessageBoxImage.Error); 108 | } 109 | }; 110 | 111 | worker.RunWorkerCompleted += (s, e) => 112 | { 113 | if (there_are_new_versions) 114 | ThereAreNewVersions?.Invoke(this, EventArgs.Empty); 115 | else 116 | NoNewVersions?.Invoke(this, EventArgs.Empty); 117 | 118 | if (errors_occured) 119 | ErrorsOccuredWhileChecking?.Invoke(this, EventArgs.Empty); 120 | 121 | CheckComplete?.Invoke(this, EventArgs.Empty); 122 | }; 123 | 124 | worker.RunWorkerAsync(); 125 | 126 | } 127 | 128 | 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /src/Classes/SelfService/SelfUpdate.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Http; 8 | using System.Net.Http.Headers; 9 | using System.Reflection; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Windows; 13 | 14 | namespace AJ_UpdateWatcher 15 | { 16 | static class SelfUpdate 17 | { 18 | const string UserAgent = "aojdk-updatewatcher Auto Updater"; 19 | static string ProductName = $"Update Watcher for {Branding.TargetProduct}"; 20 | 21 | static public string LatestVersion_DownloadURL = ""; 22 | static public string LatestVersion_BrowserURL = ""; 23 | static public string LatestVersion_ReleaseName { get; internal set; } 24 | static public string LatestVersion_ReleaseText { get; internal set; } 25 | static public string LatestVersion_ReleaseIntroText { get; internal set; } 26 | static public string LatestVersion_TagName { get; internal set; } 27 | static public bool Found = false; 28 | 29 | static public bool HasNewVersion(string api) 30 | { 31 | Version local_version = Assembly.GetEntryAssembly().GetName().Version; 32 | 33 | // for testing 34 | // local_version = new Version("0.0.0.0"); 35 | 36 | Found = false; 37 | 38 | try 39 | { 40 | IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; 41 | defaultWebProxy.Credentials = CredentialCache.DefaultCredentials; 42 | 43 | HttpClientHandler hch = new HttpClientHandler(); 44 | hch.Proxy = defaultWebProxy; 45 | 46 | //hch.Proxy = ProxyConfigurator.GetWebProxy; 47 | //hch.UseProxy = ProxyConfigurator.UseProxy; 48 | 49 | var httpClient = new HttpClient(hch); 50 | 51 | httpClient.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); 52 | httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(UserAgent); 53 | 54 | var response = httpClient.GetStringAsync(new Uri(api)).Result; 55 | JObject o = JObject.Parse(response); 56 | 57 | LatestVersion_BrowserURL = (string)o["html_url"]; 58 | 59 | LatestVersion_ReleaseName = (string)o["name"]; 60 | LatestVersion_ReleaseText = (string)o["body"]; 61 | LatestVersion_TagName = (string)o["tag_name"]; 62 | 63 | string tag = (string)o["tag_name"]; 64 | Version remote_version = new Version(tag); 65 | 66 | LatestVersion_ReleaseIntroText = LatestVersion_ReleaseText.Split(new string[] { "
" }, StringSplitOptions.RemoveEmptyEntries)[0]; 67 | 68 | var result = remote_version.CompareTo(local_version); 69 | if (result > 0) 70 | { 71 | JArray array = (JArray)o["assets"]; 72 | foreach (var a in array) 73 | { 74 | string name = (string)a["name"]; 75 | if (name.IndexOf("setup", StringComparison.OrdinalIgnoreCase) >= 0) 76 | { 77 | LatestVersion_DownloadURL = (string)a["browser_download_url"]; 78 | Found = true; 79 | break; 80 | } 81 | 82 | } 83 | } 84 | 85 | } 86 | // better not show anything here as it may interrupt user if checks are being performed as a background task 87 | catch (Exception ex) 88 | { 89 | //MessageBox.Show("There was an error: " + ex.Message, "Adoptium API Error", MessageBoxButton.OK, MessageBoxImage.Error); 90 | } 91 | 92 | return Found; 93 | } 94 | static public void DownloadCloseAndInstallUpdate() 95 | { 96 | if (!Found || LatestVersion_DownloadURL == "") return; 97 | try 98 | { 99 | Uri ur = new Uri(LatestVersion_DownloadURL); 100 | 101 | string tempname = System.IO.Path.GetTempPath() + Guid.NewGuid() + "-" + GetFileNameFromUrl(LatestVersion_DownloadURL); 102 | 103 | IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; 104 | defaultWebProxy.Credentials = CredentialCache.DefaultCredentials; 105 | 106 | using (WebClient client = new WebClient { Proxy = defaultWebProxy }) 107 | { 108 | //client.Proxy = ProxyConfigurator.GetWebProxy; 109 | 110 | client.DownloadFile(ur, tempname); 111 | 112 | MessageBox.Show($"Download complete. {Branding.ProductName} will now be closed and the new version will be installed.", ProductName + " :: Updater", MessageBoxButton.OK, MessageBoxImage.Information); 113 | Process proc = new Process(); 114 | proc.StartInfo.FileName = tempname; 115 | proc.StartInfo.UseShellExecute = true; 116 | proc.Start(); 117 | 118 | System.Windows.Application.Current.Shutdown(); 119 | } 120 | } 121 | catch (Exception ex) 122 | { 123 | MessageBox.Show("There was an error: " + ex.Message, ProductName + " Updater Error", MessageBoxButton.OK, MessageBoxImage.Error); 124 | } 125 | } 126 | static public void OpenLatestReleaseInBrowser() 127 | { 128 | Process.Start(LatestVersion_BrowserURL); 129 | } 130 | static string GetFileNameFromUrl(string url) 131 | { 132 | Uri uri; 133 | Uri SomeBaseUri = new Uri("http://canbeanything"); 134 | 135 | if (!Uri.TryCreate(url, UriKind.Absolute, out uri)) 136 | uri = new Uri(SomeBaseUri, url); 137 | 138 | return System.IO.Path.GetFileName(uri.LocalPath); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Classes/SelfService/Upgrade.cs: -------------------------------------------------------------------------------- 1 | using AJ_UpdateWatcher.Properties; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | 11 | namespace AJ_UpdateWatcher 12 | { 13 | public static class Upgrade 14 | { 15 | public static void UpgradeAppSettings() 16 | { 17 | try 18 | { 19 | //MessageBox.Show(Assembly.GetExecutingAssembly().GetName().Version.ToString()); 20 | //MessageBox.Show(Settings.Default.SettingsUpgradeRequired.ToString()); 21 | 22 | // 1. Upgrade settings 23 | if (Settings.Default.SettingsUpgradeRequired) 24 | { 25 | // we had "FirstSilentRunMessageHasBeenDisplayed" // "SettingsUpgradeComplete_from_V1" settings in v. 2.0.0.0 release but not in v.1.0.0.0 26 | // if at least one is present in previous version - we may upgrade settings 27 | bool previousVersionWasAtLeast2000 = false; 28 | if ( 29 | Settings.Default.GetPreviousVersion("FirstSilentRunMessageHasBeenDisplayed") != null || 30 | Settings.Default.GetPreviousVersion("SettingsUpgradeComplete_from_V1") != null 31 | ) 32 | previousVersionWasAtLeast2000 = true; 33 | 34 | // if previous version was at least 2.0.0.0 - we may proceed 35 | if (previousVersionWasAtLeast2000) 36 | { 37 | Version previousFormatVersion = null; 38 | 39 | // some boilerplate code for future releases 40 | if (Settings.Default.GetPreviousVersion("SettingsFormatVersion") != null) 41 | { 42 | string _previousFormatVersion = Settings.Default.GetPreviousVersion("SettingsFormatVersion") as string; 43 | previousFormatVersion = new Version(_previousFormatVersion); 44 | 45 | System.Diagnostics.Debug.WriteLine("Upgrading settings from previous version " + previousFormatVersion.ToString()); 46 | //MessageBox.Show("Your settings had been updated from previous version", Branding.MessageBoxHeader); 47 | 48 | } 49 | 50 | // we should upgrade anyway if previous >= 2.0.0.0 51 | Settings.Default.Upgrade(); 52 | 53 | // one-time highlighting during upgrade 54 | if ((previousFormatVersion??(new Version("2.0.2.0"))) < new Version("2.0.2.0")) 55 | { 56 | Settings.Default.lblHelpContextRequiresHighlighting = true; 57 | } 58 | } 59 | 60 | // update not required any more 61 | Settings.Default.SettingsUpgradeRequired = false; 62 | // we must explicitly store current version for it to be available for future upgrades 63 | Settings.Default.SettingsFormatVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 64 | // finally, save settings 65 | Settings.Default.Save(); 66 | 67 | } 68 | 69 | 70 | // 2. Upgrade scheduled tasks 71 | if (!Settings.Default.SettingsUpgradeComplete_from_V1) 72 | { 73 | const string v1TaskName = "AdoptOpenJDK_UpdateWatcher"; 74 | 75 | SchedulerManager sm = new SchedulerManager(); 76 | 77 | if (sm.TaskIsSet(v1TaskName)) 78 | { 79 | if (MessageBox.Show( 80 | $"{Branding.ProductName} has detected that you have scheduled 'check for updates' task from version 1." + Environment.NewLine + Environment.NewLine + 81 | "It is suggested to remove it and create new task." + Environment.NewLine + Environment.NewLine + 82 | "Would you like to do it? [Recommended]", 83 | $"Upgrade to v.{Assembly.GetExecutingAssembly().GetName().Version} - {Branding.MessageBoxHeader}", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes) 84 | == MessageBoxResult.Yes) 85 | { 86 | ExecuteTryUpdateScheduledTask(v1TaskName, sm); 87 | } 88 | else 89 | if (MessageBox.Show( 90 | $"In is highly important that the scheduled task will be upgraded. We ask you to reconsider your choice." + Environment.NewLine + Environment.NewLine + 91 | "Yes = Please upgrade" + Environment.NewLine + 92 | "No = Keep as is. I'm really sure what I'm doing and I will take full responsibility for upcoming errors.", 93 | $"Upgrade to v.{Assembly.GetExecutingAssembly().GetName().Version} - {Branding.MessageBoxHeader}", MessageBoxButton.YesNo, MessageBoxImage.Exclamation, MessageBoxResult.Yes) 94 | == MessageBoxResult.Yes) 95 | { 96 | ExecuteTryUpdateScheduledTask(v1TaskName, sm); 97 | } 98 | } 99 | 100 | Settings.Default.SettingsUpgradeComplete_from_V1 = true; 101 | Settings.Default.Save(); 102 | 103 | } 104 | } 105 | catch (Exception ex) { MessageBox.Show($"There was an error: [{ex.Message}]", Branding.MessageBoxHeader); }; 106 | } 107 | 108 | private static void ExecuteTryUpdateScheduledTask(string v1TaskName, SchedulerManager sm) 109 | { 110 | try 111 | { 112 | sm.DeleteTask(v1TaskName); 113 | 114 | if (!sm.TaskIsSet()) 115 | sm.InstallTask(); 116 | else 117 | sm.CheckConsistency(); 118 | } 119 | catch (Exception ex) { MessageBox.Show($"There was an error: [{ex.Message}]", Branding.MessageBoxHeader); }; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Classes/Tools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Text.RegularExpressions; 8 | using System.Diagnostics; 9 | using System.Windows; 10 | using System.ComponentModel; 11 | using AdoptOpenJDK_UpdateWatcher.Properties; 12 | 13 | namespace AdoptOpenJDK_UpdateWatcher 14 | { 15 | static class LocalInstallation 16 | { 17 | public static event PropertyChangedEventHandler StaticPropertyChanged; 18 | private static void OnStaticPropertyChanged(string propertyName) 19 | { 20 | StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName)); 21 | } 22 | 23 | static private string version_string = ""; 24 | static public string VersionString 25 | { 26 | get { return version_string; } 27 | set 28 | { 29 | version_string = value; 30 | OnStaticPropertyChanged("VersionString"); 31 | } 32 | } 33 | static private string installation_path = ""; 34 | static public string InstallationPath 35 | { 36 | get { return installation_path; } 37 | set 38 | { 39 | installation_path = value; 40 | OnStaticPropertyChanged("InstallationPath"); 41 | } 42 | } 43 | 44 | static public int VersionMajor = 0; 45 | static public int VersionMinor = 0; 46 | static public int VersionSecurity = 0; 47 | static public bool Detected = false; 48 | 49 | static public bool TryDetect() 50 | { 51 | bool detected = false; 52 | 53 | bool useJavaHome = Settings.Default.useJavaHome; 54 | 55 | if (useJavaHome) 56 | detected = CheckJavaHome(); 57 | else 58 | { 59 | string path = Settings.Default.LocalInstallationPath; 60 | if (Directory.Exists(path)) 61 | detected = CheckPath(path); 62 | } 63 | 64 | return detected; 65 | } 66 | 67 | static public bool CheckJavaHome() 68 | { 69 | var java_home = Environment.GetEnvironmentVariable("JAVA_HOME"); 70 | if (!String.IsNullOrEmpty(java_home)) 71 | return CheckPath(java_home); 72 | else return false; 73 | } 74 | 75 | static public LatestVersion GetVersion() 76 | { 77 | LatestVersion version = new LatestVersion(); 78 | 79 | version.Major = VersionMajor.ToString(); 80 | version.Minor = VersionMinor.ToString(); 81 | version.Security = VersionSecurity.ToString(); 82 | version.Found = true; 83 | version.LocalPath = InstallationPath; 84 | version.VersionString = VersionString; 85 | 86 | return version; 87 | } 88 | 89 | static public bool CheckPath(string path, bool UpdateLocalInstallationInstance = true) 90 | { 91 | if (!File.Exists(Path.Combine(path, "release"))) return false; 92 | 93 | bool found = false; 94 | bool seems_to_be_adoptopenjdk = true; 95 | 96 | ////// make sure its openjdk 97 | ////// currently we rely on 'adopt' keyword in path ... 98 | ////if (path.IndexOf("adopt", StringComparison.OrdinalIgnoreCase) >= 0 || 99 | //// path.IndexOf("openjdk", StringComparison.OrdinalIgnoreCase) >= 0) 100 | //// seems_to_be_adoptopenjdk = true; 101 | 102 | ////// ... or 'ASSEMBLY_EXCEPTION' file with 'openjdk' keyword inside 103 | ////if (!seems_to_be_adoptopenjdk) 104 | ////{ 105 | //// string ASSEMBLY_EXCEPTION = Path.Combine(path, "ASSEMBLY_EXCEPTION"); 106 | //// if (File.Exists(ASSEMBLY_EXCEPTION)) 107 | //// if (File.ReadLines(ASSEMBLY_EXCEPTION).Any(line => line.IndexOf("openjdk", StringComparison.OrdinalIgnoreCase) >= 0 )) 108 | //// seems_to_be_adoptopenjdk = true; 109 | ////} 110 | 111 | // we found the file 112 | if (seems_to_be_adoptopenjdk) 113 | { 114 | const string regex = "JAVA_VERSION=\\\"(([0-9]+)\\.([0-9]+)\\.([0-9]+)(_([0-9]+))?.*)\\\""; 115 | Regex java_version_regex = new Regex(regex, RegexOptions.IgnoreCase); 116 | 117 | StreamReader reader = File.OpenText(Path.Combine(path, "release")); 118 | 119 | string line; 120 | while ((line = reader.ReadLine()) != null) 121 | { 122 | Match match = java_version_regex.Match(line); 123 | if (match.Success) 124 | { 125 | if (UpdateLocalInstallationInstance) 126 | { 127 | VersionString = match.Groups[1].Value; 128 | 129 | int a = Convert.ToInt32(match.Groups[2].Value); 130 | int b = Convert.ToInt32(match.Groups[3].Value); 131 | int c = Convert.ToInt32(match.Groups[4].Value); 132 | 133 | int d = -1; 134 | if (match.Groups[6].Value != "") 135 | d = Convert.ToInt32(match.Groups[6].Value); 136 | 137 | 138 | if (a == 1) 139 | { 140 | VersionMajor = b; 141 | VersionMinor = c; 142 | VersionSecurity = d; 143 | } 144 | else 145 | { 146 | VersionMajor = a; 147 | VersionMinor = b; 148 | VersionSecurity = c; 149 | } 150 | } 151 | found = true; 152 | break; 153 | } 154 | } 155 | 156 | } // if (seems_to_be_adoptopenjdk) 157 | 158 | if (found && UpdateLocalInstallationInstance) 159 | { 160 | InstallationPath = path; 161 | Detected = true; 162 | } 163 | 164 | return found; 165 | } 166 | 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/Classes/ViewModels/AddInstallationFromWebViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAPICodePack.Dialogs; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.ComponentModel; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using System.Windows.Input; 12 | 13 | namespace AJ_UpdateWatcher 14 | { 15 | class AddInstallationFromWebViewModel : ViewModelBase 16 | { 17 | private Machine machine = App.Machine; 18 | private Installation newItem; 19 | 20 | public AddInstallationFromWebViewModel() 21 | { 22 | available_releases = App.AvailableReleases; 23 | NewItem = new Installation(); 24 | 25 | NewItem.PropertyChanged += (s, e) => { OnPropertyChanged("CanSelectHeapSize"); }; 26 | 27 | } 28 | 29 | 30 | 31 | public Installation NewItem 32 | { 33 | get { return newItem; } 34 | set 35 | { 36 | newItem = value; 37 | OnPropertyChanged("NewItem"); 38 | } 39 | } 40 | 41 | public FullyObservableCollection InstallationsList 42 | { 43 | get { return machine.Installations; } 44 | set { 45 | machine.Installations = value; 46 | OnPropertyChanged("InstallationsList"); 47 | } 48 | } 49 | 50 | private bool _download_immediately = true; 51 | public bool DownloadImmediately 52 | { 53 | get { return _download_immediately; } 54 | set 55 | { 56 | _download_immediately = value; 57 | OnPropertyChanged("DownloadImmediately"); 58 | OnPropertyChanged("MainButtonText"); 59 | } 60 | } 61 | public string MainButtonText 62 | { 63 | get 64 | { 65 | return DownloadImmediately ? "Get this release" : "Add selected release to list"; 66 | } 67 | } 68 | 69 | public bool CanSelectHeapSize { get { return NewItem.JVM_Implementation == "openj9"; } } 70 | 71 | public string LTSReleasesMessage { get { return "LTS Releases: " + string.Join(", ", available_releases.LTSReleases.ToArray()); } } 72 | public string YourArchMessage { get { return "Your system: " + (Environment.Is64BitOperatingSystem ? "x64" : "x32"); } } 73 | 74 | private AdoptiumAPI_AvailableReleases available_releases; 75 | public ObservableCollection AvailableReleases 76 | { 77 | // TODO: move to API (?) 78 | get 79 | { 80 | ObservableCollection list = new ObservableCollection() { AdoptiumAPI_MostRecentVerbs.MostRecentVerb, AdoptiumAPI_MostRecentVerbs.MostRecentLTSVerb }; 81 | foreach (var el in available_releases.Releases) 82 | list.Add(el); 83 | return list; 84 | } 85 | } 86 | public List JVMs { get { return AdoptiumAPI_ParameterEnumeration.JVMs; } } 87 | public List ImageTypes { get { return AdoptiumAPI_ParameterEnumeration.ImageTypes; } } 88 | public List HeapSizes { get { return AdoptiumAPI_ParameterEnumeration.HeapSizes; } } 89 | public List Archs { get { return AdoptiumAPI_ParameterEnumeration.Archs; } } 90 | 91 | 92 | #region AddInstallationCommand 93 | ICommand add_installation_command; 94 | public ICommand AddInstallationCommand 95 | { 96 | get 97 | { 98 | if (add_installation_command == null) 99 | { 100 | add_installation_command = new DelegateCommand(CanExecuteAddInstallationCommand, ExecuteAddInstallationCommand); 101 | } 102 | return add_installation_command; 103 | } 104 | } 105 | private void ExecuteAddInstallationCommand(object parameter) 106 | { 107 | var installationToAdd = newItem; 108 | NewItem = new Installation(); 109 | 110 | installationToAdd.CheckForUpdatesFlag = true; 111 | 112 | var same = from i in InstallationsList 113 | where 114 | i.WatchedRelease == installationToAdd.WatchedRelease && 115 | i.ImageType == installationToAdd.ImageType && 116 | i.JVM_Implementation == installationToAdd.JVM_Implementation && 117 | i.HeapSize == installationToAdd.HeapSize && 118 | i.Arch == installationToAdd.Arch /*&& 119 | ((i.IsAutodiscoveredInstance && i.CheckForUpdatesFlag) || !i.IsAutodiscoveredInstance)*/ 120 | 121 | select i; 122 | 123 | if (same.Count() > 0) { 124 | var same_paths = from i in same 125 | /*where (i.IsAutodiscoveredInstance && i.CheckForUpdatesFlag) || !i.IsAutodiscoveredInstance*/ 126 | select $"[{i.InstallationTypeText}{(i.CheckForUpdatesFlag?"":", Disabled")}] (set to {i.WatchedRelease}):{Environment.NewLine}{i.DisplayPath}"; 127 | if (MessageBox.Show( 128 | $"You already have {same_paths.Count()} installation{(same_paths.Count() > 1 ? "s" : "")} with the same parameters in the list:" + Environment.NewLine + Environment.NewLine + 129 | $"{String.Join(Environment.NewLine, same_paths)}" + Environment.NewLine + Environment.NewLine + 130 | $"Do you really want to add one more? [not recommended]", Branding.MessageBoxHeader, MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No 131 | ) == MessageBoxResult.No) 132 | { 133 | NewItem = installationToAdd; 134 | return; 135 | } 136 | } 137 | 138 | InstallationsList.Add(installationToAdd); 139 | 140 | if (DownloadImmediately) 141 | App.ShowNewVersionWindow(true); 142 | 143 | App.AddInstallationFromWebWindowInstance.Close(); 144 | } 145 | private bool CanExecuteAddInstallationCommand(object parameter) { return true; } 146 | #endregion 147 | 148 | public string TargetProduct { get { return Branding.TargetProduct; } } 149 | public string ProductName { get { return Branding.ProductName; } } 150 | 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Classes/SelfService/AppDataPersistence.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Xml.Serialization; 10 | 11 | namespace AJ_UpdateWatcher 12 | { 13 | static class AppDataPersistence 14 | { 15 | static public string MachineDataPath { 16 | get 17 | { 18 | var folder = Path.Combine( 19 | Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 20 | "AJUpdateWatcher" 21 | ); 22 | 23 | if (!Directory.Exists(folder)) 24 | { 25 | try 26 | { 27 | Directory.CreateDirectory(folder); 28 | } 29 | catch (Exception ex) 30 | { 31 | MessageBox.Show($"There was an error: [ {ex.Message} ].", "Error creating folder", MessageBoxButton.OK, MessageBoxImage.Error); 32 | } 33 | } 34 | 35 | return Path.Combine(folder, "machine_settings.xml"); 36 | } 37 | } 38 | 39 | static public bool Save(Machine machine) 40 | { 41 | return Save(machine, AppDataPersistence.MachineDataPath); 42 | } 43 | static public bool Save(Machine machine, string filename) 44 | { 45 | try 46 | { 47 | XmlSerializer xs = new XmlSerializer(typeof(Machine)); 48 | TextWriter tw = new StreamWriter(filename); 49 | xs.Serialize(tw, machine); 50 | 51 | //using (Stream stream = File.Open(filename, FileMode.Create)) 52 | //{ 53 | // var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 54 | // binaryFormatter.Serialize(stream, machine); 55 | //} 56 | 57 | tw.Close(); 58 | 59 | return true; 60 | } 61 | catch (Exception ex) 62 | { 63 | MessageBox.Show($"There was an error: [ {ex.Message} ].", "Error while saving the configuration", MessageBoxButton.OK, MessageBoxImage.Error); 64 | return false; 65 | } 66 | } 67 | 68 | static public Machine TryLoad() 69 | { 70 | return TryLoad(AppDataPersistence.MachineDataPath); 71 | } 72 | static public Machine TryLoad(string filename) 73 | { 74 | if (File.Exists(filename)) 75 | { 76 | try 77 | { 78 | using (var sr = new StreamReader(filename)) 79 | { 80 | XmlSerializer xs = new XmlSerializer(typeof(Machine)); 81 | Machine loaded = (Machine)xs.Deserialize(sr); 82 | 83 | Machine machine = new Machine(); 84 | 85 | foreach (Installation i in loaded.Installations) 86 | { 87 | // we should re-discover them again, they should not be persistent 88 | if (i.IsAutodiscoveredInstance) 89 | continue; 90 | 91 | if (String.IsNullOrEmpty(i.Path)) 92 | continue; 93 | 94 | Installation new_installation; 95 | 96 | if (i.java_home_instance) 97 | new_installation = new Installation(true); 98 | else 99 | new_installation = new Installation(i.Path); 100 | 101 | // we need to set these up after initialization to override constructor/propertychanged logic 102 | // except for autodiscovered instances 103 | if (!i.IsAutodiscoveredInstance) // normally this should always be triggered 104 | { 105 | new_installation.WatchedRelease = i.WatchedRelease; 106 | new_installation.JVM_Implementation = i.JVM_Implementation; 107 | new_installation.ImageType = i.ImageType; 108 | new_installation.Arch = i.Arch; 109 | new_installation.HeapSize = i.HeapSize; 110 | new_installation.SkippedReleaseName = i.SkippedReleaseName; 111 | new_installation.CheckForUpdatesFlag = i.CheckForUpdatesFlag; 112 | } 113 | 114 | machine.Installations.Add(new_installation); 115 | } 116 | 117 | machine.ActivateAutoDiscoveryOnPropertyChange(); 118 | 119 | machine.DiscoverMachineWideInstallations = loaded.DiscoverMachineWideInstallations; 120 | machine.DiscoverUserScopeInstallations = loaded.DiscoverUserScopeInstallations; 121 | machine.ShowShadowedInstallations = loaded.ShowShadowedInstallations; 122 | 123 | foreach (Installation ai in loaded.Installations.Where(x => x.IsAutodiscoveredInstance && x.HasSkippedRelease)) 124 | { 125 | (machine.Installations.Where(m => m.IsAutodiscoveredInstance && m.Path == ai.Path).First()).SkippedReleaseName = ai.SkippedReleaseName; 126 | } 127 | 128 | machine.SomethingHasBeenChangedSinceUpdateCheck = false; 129 | 130 | return machine; 131 | } 132 | 133 | //using (Stream stream = File.Open(filename, FileMode.Open)) 134 | //{ 135 | // var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 136 | // return (Machine)binaryFormatter.Deserialize(stream); 137 | //} 138 | 139 | } 140 | catch (Exception ex) { MessageBox.Show($"There was an error: [ {ex.Message} ].", "Error while loading the configuration", MessageBoxButton.OK, MessageBoxImage.Error); } 141 | } 142 | // quasi - else: 143 | Debug.WriteLine($"Machine settings [{filename}] not found, loading default machine with auto-discovery enabled."); 144 | 145 | // create new Machine with default settings 146 | Machine default_machine = new Machine(); 147 | 148 | default_machine.ActivateAutoDiscoveryOnPropertyChange(); // not needed now, required for further changes 149 | default_machine.RefreshAutoDiscoveredInstallations(); // actually try to find the installations 150 | 151 | return default_machine; 152 | 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 17 | 18 | 19 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _Playground 2 | SetupOutput 3 | installer-src 4 | *.iss 5 | info_before.txt 6 | *.wsb 7 | 8 | 9 | ## Ignore Visual Studio temporary files, build results, and 10 | ## files generated by popular Visual Studio add-ons. 11 | ## 12 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 13 | 14 | # User-specific files 15 | *.rsuser 16 | *.suo 17 | *.user 18 | *.userosscache 19 | *.sln.docstates 20 | 21 | # User-specific files (MonoDevelop/Xamarin Studio) 22 | *.userprefs 23 | 24 | # Mono auto generated files 25 | mono_crash.* 26 | 27 | # Build results 28 | [Dd]ebug/ 29 | [Dd]ebugPublic/ 30 | [Rr]elease/ 31 | [Rr]eleases/ 32 | x64/ 33 | x86/ 34 | [Ww][Ii][Nn]32/ 35 | [Aa][Rr][Mm]/ 36 | [Aa][Rr][Mm]64/ 37 | bld/ 38 | [Bb]in/ 39 | [Oo]bj/ 40 | [Ll]og/ 41 | [Ll]ogs/ 42 | 43 | # Visual Studio 2015/2017 cache/options directory 44 | .vs/ 45 | # Uncomment if you have tasks that create the project's static files in wwwroot 46 | #wwwroot/ 47 | 48 | # Visual Studio 2017 auto generated files 49 | Generated\ Files/ 50 | 51 | # MSTest test Results 52 | [Tt]est[Rr]esult*/ 53 | [Bb]uild[Ll]og.* 54 | 55 | # NUnit 56 | *.VisualState.xml 57 | TestResult.xml 58 | nunit-*.xml 59 | 60 | # Build Results of an ATL Project 61 | [Dd]ebugPS/ 62 | [Rr]eleasePS/ 63 | dlldata.c 64 | 65 | # Benchmark Results 66 | BenchmarkDotNet.Artifacts/ 67 | 68 | # .NET Core 69 | project.lock.json 70 | project.fragment.lock.json 71 | artifacts/ 72 | 73 | # ASP.NET Scaffolding 74 | ScaffoldingReadMe.txt 75 | 76 | # StyleCop 77 | StyleCopReport.xml 78 | 79 | # Files built by Visual Studio 80 | *_i.c 81 | *_p.c 82 | *_h.h 83 | *.ilk 84 | *.meta 85 | *.obj 86 | *.iobj 87 | *.pch 88 | *.pdb 89 | *.ipdb 90 | *.pgc 91 | *.pgd 92 | *.rsp 93 | *.sbr 94 | *.tlb 95 | *.tli 96 | *.tlh 97 | *.tmp 98 | *.tmp_proj 99 | *_wpftmp.csproj 100 | *.log 101 | *.vspscc 102 | *.vssscc 103 | .builds 104 | *.pidb 105 | *.svclog 106 | *.scc 107 | 108 | # Chutzpah Test files 109 | _Chutzpah* 110 | 111 | # Visual C++ cache files 112 | ipch/ 113 | *.aps 114 | *.ncb 115 | *.opendb 116 | *.opensdf 117 | *.sdf 118 | *.cachefile 119 | *.VC.db 120 | *.VC.VC.opendb 121 | 122 | # Visual Studio profiler 123 | *.psess 124 | *.vsp 125 | *.vspx 126 | *.sap 127 | 128 | # Visual Studio Trace Files 129 | *.e2e 130 | 131 | # TFS 2012 Local Workspace 132 | $tf/ 133 | 134 | # Guidance Automation Toolkit 135 | *.gpState 136 | 137 | # ReSharper is a .NET coding add-in 138 | _ReSharper*/ 139 | *.[Rr]e[Ss]harper 140 | *.DotSettings.user 141 | 142 | # TeamCity is a build add-in 143 | _TeamCity* 144 | 145 | # DotCover is a Code Coverage Tool 146 | *.dotCover 147 | 148 | # AxoCover is a Code Coverage Tool 149 | .axoCover/* 150 | !.axoCover/settings.json 151 | 152 | # Coverlet is a free, cross platform Code Coverage Tool 153 | coverage*[.json, .xml, .info] 154 | 155 | # Visual Studio code coverage results 156 | *.coverage 157 | *.coveragexml 158 | 159 | # NCrunch 160 | _NCrunch_* 161 | .*crunch*.local.xml 162 | nCrunchTemp_* 163 | 164 | # MightyMoose 165 | *.mm.* 166 | AutoTest.Net/ 167 | 168 | # Web workbench (sass) 169 | .sass-cache/ 170 | 171 | # Installshield output folder 172 | [Ee]xpress/ 173 | 174 | # DocProject is a documentation generator add-in 175 | DocProject/buildhelp/ 176 | DocProject/Help/*.HxT 177 | DocProject/Help/*.HxC 178 | DocProject/Help/*.hhc 179 | DocProject/Help/*.hhk 180 | DocProject/Help/*.hhp 181 | DocProject/Help/Html2 182 | DocProject/Help/html 183 | 184 | # Click-Once directory 185 | publish/ 186 | 187 | # Publish Web Output 188 | *.[Pp]ublish.xml 189 | *.azurePubxml 190 | # Note: Comment the next line if you want to checkin your web deploy settings, 191 | # but database connection strings (with potential passwords) will be unencrypted 192 | *.pubxml 193 | *.publishproj 194 | 195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 196 | # checkin your Azure Web App publish settings, but sensitive information contained 197 | # in these scripts will be unencrypted 198 | PublishScripts/ 199 | 200 | # NuGet Packages 201 | *.nupkg 202 | # NuGet Symbol Packages 203 | *.snupkg 204 | # The packages folder can be ignored because of Package Restore 205 | **/[Pp]ackages/* 206 | # except build/, which is used as an MSBuild target. 207 | !**/[Pp]ackages/build/ 208 | # Uncomment if necessary however generally it will be regenerated when needed 209 | #!**/[Pp]ackages/repositories.config 210 | # NuGet v3's project.json files produces more ignorable files 211 | *.nuget.props 212 | *.nuget.targets 213 | 214 | # Microsoft Azure Build Output 215 | csx/ 216 | *.build.csdef 217 | 218 | # Microsoft Azure Emulator 219 | ecf/ 220 | rcf/ 221 | 222 | # Windows Store app package directories and files 223 | AppPackages/ 224 | BundleArtifacts/ 225 | Package.StoreAssociation.xml 226 | _pkginfo.txt 227 | *.appx 228 | *.appxbundle 229 | *.appxupload 230 | 231 | # Visual Studio cache files 232 | # files ending in .cache can be ignored 233 | *.[Cc]ache 234 | # but keep track of directories ending in .cache 235 | !?*.[Cc]ache/ 236 | 237 | # Others 238 | ClientBin/ 239 | ~$* 240 | *~ 241 | *.dbmdl 242 | *.dbproj.schemaview 243 | *.jfm 244 | *.pfx 245 | *.publishsettings 246 | orleans.codegen.cs 247 | 248 | # Including strong name files can present a security risk 249 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 250 | #*.snk 251 | 252 | # Since there are multiple workflows, uncomment next line to ignore bower_components 253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 254 | #bower_components/ 255 | 256 | # RIA/Silverlight projects 257 | Generated_Code/ 258 | 259 | # Backup & report files from converting an old project file 260 | # to a newer Visual Studio version. Backup files are not needed, 261 | # because we have git ;-) 262 | _UpgradeReport_Files/ 263 | Backup*/ 264 | UpgradeLog*.XML 265 | UpgradeLog*.htm 266 | ServiceFabricBackup/ 267 | *.rptproj.bak 268 | 269 | # SQL Server files 270 | *.mdf 271 | *.ldf 272 | *.ndf 273 | 274 | # Business Intelligence projects 275 | *.rdl.data 276 | *.bim.layout 277 | *.bim_*.settings 278 | *.rptproj.rsuser 279 | *- [Bb]ackup.rdl 280 | *- [Bb]ackup ([0-9]).rdl 281 | *- [Bb]ackup ([0-9][0-9]).rdl 282 | 283 | # Microsoft Fakes 284 | FakesAssemblies/ 285 | 286 | # GhostDoc plugin setting file 287 | *.GhostDoc.xml 288 | 289 | # Node.js Tools for Visual Studio 290 | .ntvs_analysis.dat 291 | node_modules/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio LightSwitch build output 303 | **/*.HTMLClient/GeneratedArtifacts 304 | **/*.DesktopClient/GeneratedArtifacts 305 | **/*.DesktopClient/ModelManifest.xml 306 | **/*.Server/GeneratedArtifacts 307 | **/*.Server/ModelManifest.xml 308 | _Pvt_Extensions 309 | 310 | # Paket dependency manager 311 | .paket/paket.exe 312 | paket-files/ 313 | 314 | # FAKE - F# Make 315 | .fake/ 316 | 317 | # CodeRush personal settings 318 | .cr/personal 319 | 320 | # Python Tools for Visual Studio (PTVS) 321 | __pycache__/ 322 | *.pyc 323 | 324 | # Cake - Uncomment if you are using it 325 | # tools/** 326 | # !tools/packages.config 327 | 328 | # Tabs Studio 329 | *.tss 330 | 331 | # Telerik's JustMock configuration file 332 | *.jmconfig 333 | 334 | # BizTalk build output 335 | *.btp.cs 336 | *.btm.cs 337 | *.odx.cs 338 | *.xsd.cs 339 | 340 | # OpenCover UI analysis results 341 | OpenCover/ 342 | 343 | # Azure Stream Analytics local run output 344 | ASALocalRun/ 345 | 346 | # MSBuild Binary and Structured Log 347 | *.binlog 348 | 349 | # NVidia Nsight GPU debugger configuration file 350 | *.nvuser 351 | 352 | # MFractors (Xamarin productivity tool) working folder 353 | .mfractor/ 354 | 355 | # Local History for Visual Studio 356 | .localhistory/ 357 | 358 | # BeatPulse healthcheck temp database 359 | healthchecksdb 360 | 361 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 362 | MigrationBackup/ 363 | 364 | # Ionide (cross platform F# VS Code tools) working folder 365 | .ionide/ 366 | 367 | # Fody - auto-generated XML schema 368 | FodyWeavers.xsd 369 | -------------------------------------------------------------------------------- /src/ConfigurationWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | using Microsoft.WindowsAPICodePack.Dialogs; 17 | using AJ_UpdateWatcher.Properties; 18 | using Microsoft.Win32.TaskScheduler; 19 | using System.Diagnostics; 20 | using System.Configuration; 21 | 22 | namespace AJ_UpdateWatcher 23 | { 24 | /// 25 | /// Interaction logic for MainWindow.xaml 26 | /// 27 | public partial class ConfigurationWindow : Window 28 | { 29 | HelpHowToInstallNewWindow HelpHowToInstallNewWindow; 30 | SettingsWindow SettingsWindowInstance; 31 | 32 | ConfigurationViewModel ConfigurationVM = new ConfigurationViewModel(); 33 | 34 | public ConfigurationWindow() 35 | { 36 | InitializeComponent(); 37 | this.DataContext = ConfigurationVM; 38 | } 39 | 40 | private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) 41 | { 42 | ConfigurationVM.SaveModel(); 43 | 44 | Settings.Default.Save(); 45 | 46 | if (!Settings.Default.isConfigured && (bool)cbSchedule.IsChecked == false) 47 | { 48 | var ans = MessageBox.Show( 49 | $"Did you forget to configure to check for {Branding.TargetProduct} JDK/JRE Updates on User Logon?" + Environment.NewLine + Environment.NewLine + 50 | "Yes = go back and enable this feature [Recommended]" + Environment.NewLine + "No = exit without enabling scheduled update check.", 51 | Branding.MessageBoxHeader, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes); 52 | if (ans == MessageBoxResult.Yes) 53 | { 54 | e.Cancel = true; 55 | gridSchedule.Background = /*gridSchedule.Background == Brushes.LightGoldenrodYellow ? */ 56 | Brushes.Yellow /*: Brushes.LightGoldenrodYellow*/; 57 | return; 58 | } 59 | } 60 | if (!Settings.Default.isConfigured) 61 | { 62 | if ( App.Machine.PossiblyHasConfiguredInstallations ) 63 | { 64 | Settings.Default.isConfigured = true; 65 | Settings.Default.Save(); 66 | } 67 | } 68 | 69 | } 70 | private void DataGrid_Unloaded(object sender, RoutedEventArgs e) 71 | { 72 | var grid = (DataGrid)sender; 73 | grid.CommitEdit(DataGridEditingUnit.Row, true); 74 | } 75 | 76 | private void DataGridCell_Selected(object sender, RoutedEventArgs e) 77 | { 78 | try 79 | { 80 | // Lookup for the source to be DataGridCell 81 | if (e.OriginalSource.GetType() == typeof(DataGridCell) && 82 | !((e.OriginalSource as DataGridCell).Column.DisplayIndex == 0 || 83 | (sender as DataGrid).CurrentCell.Column.DisplayIndex == 0) 84 | ) 85 | { 86 | (sender as DataGrid).BeginEdit(e); 87 | } 88 | } 89 | catch (Exception) { } 90 | } 91 | 92 | private void Window_Loaded(object sender, RoutedEventArgs e) 93 | { 94 | App.SetUpdateCheckErrorCount(0); 95 | 96 | if (!Settings.Default.isConfigured && (bool)cbSchedule.IsChecked == false) 97 | gridSchedule.Background = Brushes.LightGoldenrodYellow; 98 | 99 | //if (!Settings.Default.isConfigured) 100 | //lblGrayedOut.Foreground = Brushes.IndianRed; 101 | 102 | if (Settings.Default.lblHelpContextRequiresHighlighting) 103 | { 104 | lblHelpContext1.Background = Brushes.LightGoldenrodYellow; 105 | lblHelpContext2.Background = Brushes.Yellow; 106 | 107 | Settings.Default.lblHelpContextRequiresHighlighting = false; 108 | } 109 | 110 | } 111 | 112 | private void btnEditEnvironmentVariables_Click(object sender, RoutedEventArgs e) 113 | { 114 | try 115 | { 116 | Process proc = new Process(); 117 | proc.StartInfo.FileName = "rundll32.exe"; 118 | proc.StartInfo.Arguments = "sysdm.cpl,EditEnvironmentVariables"; 119 | proc.StartInfo.UseShellExecute = true; 120 | proc.StartInfo.Verb = "runas"; 121 | proc.Start(); 122 | } 123 | catch (Exception) 124 | { 125 | Process.Start("rundll32.exe", "sysdm.cpl,EditEnvironmentVariables"); 126 | } 127 | 128 | } 129 | 130 | private void lblCopyright_MouseUp(object sender, MouseButtonEventArgs e) 131 | { 132 | //Process.Start("https://github.com/tushev"); 133 | } 134 | 135 | private void btnShowNewVersionWindow_Click(object sender, RoutedEventArgs e) 136 | { 137 | App.ShowNewVersionWindow(true); 138 | } 139 | 140 | private void btnWhatJREJDK_Click(object sender, RoutedEventArgs e) 141 | { 142 | AdoptiumHelpMessagesActions.ShowWhatJREJDKHelp(); 143 | } 144 | 145 | private void btnWhatImpl_Click(object sender, RoutedEventArgs e) 146 | { 147 | AdoptiumHelpMessagesActions.ShowJVM_ImplementationHelp(); 148 | } 149 | 150 | private void lblLTS_MouseUp(object sender, MouseButtonEventArgs e) 151 | { 152 | AdoptiumHelpMessagesActions.ShowLTSHelp(); 153 | } 154 | 155 | private void btnStarOnGithub_Click(object sender, RoutedEventArgs e) 156 | { 157 | Process.Start("https://github.com/tushev/aojdk-updatewatcher/stargazers"); 158 | } 159 | 160 | private void btnOpenHelpHowToInstallNewWindow_Click(object sender, RoutedEventArgs e) 161 | { 162 | if (HelpHowToInstallNewWindow == null || HelpHowToInstallNewWindow.IsLoaded == false) 163 | { 164 | HelpHowToInstallNewWindow = new HelpHowToInstallNewWindow(); 165 | HelpHowToInstallNewWindow.Show(); 166 | } 167 | else 168 | HelpHowToInstallNewWindow.Activate(); 169 | } 170 | 171 | private void btnWhatHeap_Click(object sender, RoutedEventArgs e) 172 | { 173 | AdoptiumHelpMessagesActions.ShowHeapHelp(); 174 | } 175 | 176 | private void cbSchedule_Checked(object sender, RoutedEventArgs e) 177 | { 178 | if (!Settings.Default.isConfigured) 179 | gridSchedule.Background = Brushes.Transparent; 180 | } 181 | 182 | private void btnOpenHelp_Click(object sender, RoutedEventArgs e) 183 | { 184 | Process.Start("https://github.com/tushev/aojdk-updatewatcher/wiki"); 185 | } 186 | 187 | private void btnOpenSettings_Click(object sender, RoutedEventArgs e) 188 | { 189 | if (SettingsWindowInstance == null || SettingsWindowInstance.IsLoaded == false) 190 | { 191 | SettingsWindowInstance = new SettingsWindow(); 192 | SettingsWindowInstance.Owner = this; 193 | SettingsWindowInstance.Show(); 194 | } 195 | else 196 | SettingsWindowInstance.Activate(); 197 | } 198 | 199 | 200 | private void btnHowEditGrayedOut_Click(object sender, RoutedEventArgs e) 201 | { 202 | Process.Start("https://github.com/tushev/aojdk-updatewatcher/wiki/Types-of-installations"); 203 | } 204 | 205 | private void btnHowDisableUpdates_Click(object sender, RoutedEventArgs e) 206 | { 207 | Process.Start("https://github.com/tushev/aojdk-updatewatcher/wiki/Types-of-installations#-usage-scenario-disable-updates-check-for-one-of-auto-discovered-installations"); 208 | } 209 | } 210 | 211 | 212 | 213 | } 214 | -------------------------------------------------------------------------------- /src/Classes/Updater/Updater.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AJ_UpdateWatcher 9 | { 10 | public enum UpdaterState 11 | { 12 | UpdateCheckNotPerformed, 13 | UpdateCheckInProgress, 14 | UpdateCheckComplete, 15 | UpdateInstallationInProgress, 16 | UpdateInstallationComplete 17 | } 18 | public class Updater : ViewModelBase 19 | { 20 | private UpdateChecker updateChecker = new UpdateChecker(); 21 | private UpdateInstaller updateInstaller = new UpdateInstaller(); 22 | 23 | private UpdaterState _state; 24 | private bool updatecheck_queued = false; 25 | 26 | public EventHandler InstallerProgressChanged; 27 | public EventHandler StateChanged; 28 | 29 | public event EventHandler UpdatesCheckComplete; 30 | public event EventHandler UpdatesInstallationStarted; 31 | public event EventHandler UpdatesInstallationComplete; 32 | 33 | public List ErrorsEncounteredWhileCheckingForUpdates; 34 | 35 | private Machine machine; 36 | public Updater(Machine _parent) 37 | { 38 | machine = _parent; 39 | SetToInitialState(); 40 | 41 | updateChecker.ThereAreNewVersions += (s, _e) => { UpdateCheckResultedInNewVersions = true; }; 42 | updateChecker.NoNewVersions += (s, _e) => { UpdateCheckResultedInNewVersions = false; }; 43 | updateChecker.ErrorsOccuredWhileChecking += (s, _e) => 44 | { 45 | ErrorsEncounteredWhileCheckingForUpdates = updateChecker.ErrorsEncountered; 46 | ErrorsOccuredWhileCheckingForUpdates = true; 47 | }; 48 | updateChecker.CheckComplete += (s, _e) => 49 | { 50 | State = UpdaterState.UpdateCheckComplete; 51 | UpdatesCheckComplete?.Invoke(this, _e); 52 | 53 | if (updatecheck_queued) 54 | { 55 | updatecheck_queued = false; 56 | Debug.WriteLine("updateChecker.CheckComplete: running queued CheckForUpdatesAsync"); 57 | CheckForUpdatesAsync(); 58 | }; 59 | }; 60 | 61 | updateInstaller.UpdateProcessStarted += (s, _e) => 62 | { 63 | State = UpdaterState.UpdateInstallationInProgress; 64 | UpdatesInstallationStarted?.Invoke(this, _e); 65 | }; 66 | updateInstaller.ProgressChanged += (s, _e) => { InstallerProgressChanged?.Invoke(s, _e); }; 67 | updateInstaller.ErrorsOccuredWhileUpdating += (s, _e) => { ErrorsOccuredWhileInstallingUpdates = true; }; 68 | updateInstaller.UpdateProcessCompleted += (s, _e) => 69 | { 70 | State = UpdaterState.UpdateInstallationComplete; 71 | UpdatesInstallationComplete?.Invoke(this, _e); 72 | }; 73 | } 74 | 75 | public void SetToInitialState() 76 | { 77 | ErrorsEncounteredWhileCheckingForUpdates = null; 78 | State = UpdaterState.UpdateCheckNotPerformed; 79 | } 80 | 81 | public void CheckForUpdatesAsync() 82 | { 83 | if (_state == UpdaterState.UpdateInstallationInProgress) 84 | { 85 | Debug.WriteLine("Updater.CheckForUpdatesAsync: UpdateInstallationInProgress => Rejected"); 86 | return; 87 | } 88 | if (_state == UpdaterState.UpdateCheckInProgress) 89 | { 90 | updatecheck_queued = true; 91 | Debug.WriteLine("Updater.CheckForUpdatesAsync: UpdateCheckInProgress => Queued"); 92 | return; 93 | } 94 | 95 | 96 | Debug.WriteLine("Started Updater.CheckForUpdatesAsync..."); 97 | SetToInitialState(); 98 | State = UpdaterState.UpdateCheckInProgress; 99 | 100 | updateChecker.CheckAsync(machine); 101 | } 102 | public void DownloadAndInstallUpdatesAsync() 103 | { 104 | updateInstaller.DownloadAndInstallUpdatesAsync(machine); 105 | } 106 | 107 | public UpdaterState State 108 | { 109 | get { return _state; } 110 | private set 111 | { 112 | _state = value; 113 | 114 | if (_state == UpdaterState.UpdateCheckNotPerformed) 115 | { 116 | UpdateCheckPerformed = false; 117 | UpdateCheckResultedInNewVersions = false; 118 | ErrorsOccuredWhileCheckingForUpdates = false; 119 | UpdateInstallationComplete = false; 120 | ErrorsOccuredWhileInstallingUpdates = false; 121 | } 122 | if (_state == UpdaterState.UpdateCheckComplete) 123 | { 124 | machine.SomethingHasBeenChangedSinceUpdateCheck = false; 125 | UpdateCheckPerformed = true; 126 | } 127 | if (_state == UpdaterState.UpdateInstallationComplete) 128 | { 129 | UpdateInstallationComplete = true; 130 | 131 | machine.RemoveNotInstalledCheckedInstallations(); 132 | 133 | if (RefreshAutoDiscoveredInstancesOnInstallationCompletion) 134 | machine.RefreshAutoDiscoveredInstallations(); 135 | 136 | machine.ApplyInstallationPathsToDisable(); 137 | } 138 | 139 | OnPropertyChanged("State"); 140 | 141 | OnPropertyChanged("SomethingInProgress"); 142 | OnPropertyChanged("UpdateCheckInProgress"); 143 | OnPropertyChanged("UpdateInstallationInProgress"); 144 | 145 | StateChanged?.Invoke(this, EventArgs.Empty); 146 | } 147 | } 148 | 149 | public bool RefreshAutoDiscoveredInstancesOnInstallationCompletion { get; set; } 150 | 151 | #region Progress State-reflecting Properties 152 | public bool SomethingInProgress { 153 | get { return State == UpdaterState.UpdateCheckInProgress || State == UpdaterState.UpdateInstallationInProgress; } 154 | } 155 | public bool UpdateCheckInProgress 156 | { 157 | get { return State == UpdaterState.UpdateCheckInProgress; } 158 | } 159 | public bool UpdateInstallationInProgress 160 | { 161 | get { return State == UpdaterState.UpdateInstallationInProgress; } 162 | } 163 | #endregion 164 | 165 | #region Update Checking Properties 166 | private bool _update_check_performed = false; 167 | public bool UpdateCheckPerformed { 168 | get { return _update_check_performed; } 169 | private set 170 | { 171 | _update_check_performed = value; 172 | OnPropertyChanged("UpdateCheckPerformed"); 173 | OnPropertyChanged("AllInstallationsAreUpToDate"); 174 | } 175 | } 176 | 177 | private bool _there_are_new_versions = false; 178 | public bool UpdateCheckResultedInNewVersions 179 | { 180 | get { return _there_are_new_versions; } 181 | private set 182 | { 183 | _there_are_new_versions = value; 184 | OnPropertyChanged("UpdateCheckResultedInNewVersions"); 185 | OnPropertyChanged("AllInstallationsAreUpToDate"); 186 | } 187 | } 188 | 189 | private bool _errors_occured_while_checking_for_updates = false; 190 | public bool ErrorsOccuredWhileCheckingForUpdates 191 | { 192 | get { return _errors_occured_while_checking_for_updates; } 193 | private set 194 | { 195 | _errors_occured_while_checking_for_updates = value; 196 | OnPropertyChanged("ErrorsOccuredWhileCheckingForUpdates"); 197 | } 198 | } 199 | #endregion 200 | 201 | #region Update Installation Properties 202 | private bool _update_installation_complete = false; 203 | public bool UpdateInstallationComplete 204 | { 205 | get { return _update_installation_complete; } 206 | private set 207 | { 208 | _update_installation_complete = value; 209 | OnPropertyChanged("UpdateInstallationComplete"); 210 | OnPropertyChanged("AllInstallationsAreUpToDate"); 211 | } 212 | } 213 | 214 | private bool _errors_occured_while_installing_updates = false; 215 | public bool ErrorsOccuredWhileInstallingUpdates 216 | { 217 | get { return _errors_occured_while_installing_updates; } 218 | private set 219 | { 220 | _errors_occured_while_installing_updates = value; 221 | OnPropertyChanged("ErrorsOccuredWhileInstallingUpdates"); 222 | } 223 | } 224 | #endregion 225 | 226 | public bool AllInstallationsAreUpToDate 227 | { 228 | get { return (UpdateCheckPerformed && !UpdateCheckResultedInNewVersions) || UpdateInstallationComplete; } 229 | } 230 | 231 | } 232 | } 233 | --------------------------------------------------------------------------------