From d5f0e9ed8c967cb55e057fcb39c1b700934c3463 Mon Sep 17 00:00:00 2001 From: James Dunkerley Date: Mon, 18 Nov 2024 22:29:34 +0000 Subject: [PATCH 01/15] Fixes a few bits... (#11581) - Minor fixes from past PR. - Always use Table viz for Table. - Fix display to `Always` for any AWS required parameters. - Add widget for `Redshift` credentials and alter `Username_And_Password` to require arguments. - Fix display in `Data` module methods for required parameters. - Fix `Statistic.bulk_widget`. - Alter `Google_Analytics` so credentials the first parameter. - Add support for storing the credential file in Enso cloud in `Google_Analytics`. ![image](https://github.com/user-attachments/assets/f34c4231-9f9f-468b-90e9-bbc7f2374d22) --- .../lib/Standard/AWS/0.0.0-dev/src/AWS.enso | 1 + .../AWS/0.0.0-dev/src/AWS_Credential.enso | 5 +- .../Database/Redshift/Redshift_Details.enso | 10 +++- .../lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso | 3 + .../lib/Standard/Base/0.0.0-dev/src/Data.enso | 8 +-- .../Base/0.0.0-dev/src/Data/Statistics.enso | 7 +-- .../src/Data/Statistics/Extensions.enso | 4 +- .../0.0.0-dev/src/Connection/Credentials.enso | 9 ++- .../0.0.0-dev/src/Google_Analytics.enso | 55 ++++++++++--------- .../src/Google_Analytics_Account.enso | 7 ++- .../src/Google_Analytics_Property.enso | 14 +++-- .../0.0.0-dev/src/Google_Credential.enso | 29 +++++++--- .../Standard/Table/0.0.0-dev/src/Table.enso | 12 ++-- .../Visualization/0.0.0-dev/src/Helpers.enso | 6 +- .../0.0.0-dev/src/Table/Visualization.enso | 13 ++++- test/Visualization_Tests/src/Id_Spec.enso | 4 +- 16 files changed, 113 insertions(+), 74 deletions(-) diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS.enso index 29c98d8a07..1cd388b358 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS.enso @@ -95,6 +95,7 @@ type AWS Arguments: - uri: The URI to resolve. + @uri (Text_Input display=..Always) resolve_region_and_service : URI -> AWS_Region_Service resolve_region_and_service (uri:URI=(Missing_Argument.throw "uri")) = region_regex = regex "^(([a-z]{2}-[^.]+?-\d+)|(global))$" diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso index b0a26338c5..953640e9f5 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/AWS_Credential.enso @@ -115,9 +115,10 @@ type AWS_Credential to_display_text self -> Text = self.to_text.to_display_text ## PRIVATE - default_widget (display : Display = ..When_Modified) -> Widget = + default_widget (add_user_password:Boolean=False) (display : Display = ..When_Modified) -> Widget = default = Option "Default" "..Default" profile = Option "Profile" "..Profile" [["profile", make_single_choice AWS_Credential.profile_names]] key = Option "Key" "..Key" [["access_key_id", make_text_secret_selector], ["secret_access_key", make_text_secret_selector]] + user_password = if add_user_password then [Option "Username_And_Password" "..Username_And_Password"] else [] with_config = Option "With_Configuration" "..With_Configuration" - Widget.Single_Choice values=[default, profile, key, with_config] display=display + Widget.Single_Choice values=[default, profile, key, with_config]+user_password display=display diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Redshift_Details.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Redshift_Details.enso index fdc78a13a0..46e00cbd80 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Redshift_Details.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Redshift_Details.enso @@ -31,7 +31,15 @@ type Redshift_Details - use_ssl: Whether to use SSL (defaults to `SSL_Mode.Require`). - client_cert: The client certificate to use or `Nothing` if not needed. @host (Text_Input display=..Always) - Redshift (host:Text=(Missing_Argument.throw "host")) (port:Integer=5439) (schema:Text='') (db_user:Text='') (credentials:Credentials|AWS_Credential=AWS_Credential.Profile) (use_ssl:SSL_Mode=..Require) (client_cert:Client_Certificate|Nothing=Nothing) + @credentials AWS_Credential.default_widget add_user_password=True + Redshift + host:Text=(Missing_Argument.throw "host") + port:Integer=5439 + schema:Text='' + db_user:Text='' + credentials:Credentials|AWS_Credential=..Profile + use_ssl:SSL_Mode=..Require + client_cert:Client_Certificate|Nothing=Nothing ## PRIVATE Attempt to resolve the constructor. diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso index 737fea94ed..d34b18947a 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3.enso @@ -1,5 +1,6 @@ from Standard.Base import all import Standard.Base.Errors.Common.Missing_Argument +import Standard.Base.Metadata.Widget.Text_Input import Standard.Base.Network.HTTP.Response_Body.Response_Body import Standard.Base.System.File_Format_Metadata.File_Format_Metadata import Standard.Base.System.Input_Stream.Input_Stream @@ -71,6 +72,7 @@ list_buckets credentials:AWS_Credential=..Default = handle_s3_errors <| - If the bucket does not exist, an `S3_Bucket_Not_Found` error is thrown. - If more items are available than the `max_count` parameter, a `More_Records_Available` warning is attached to the result. +@bucket (Text_Input display=..Always) @credentials AWS_Credential.default_widget list_objects : Text -> Text -> AWS_Credential -> Integer -> Vector S3_File ! S3_Error list_objects (bucket : Text = Missing_Argument.throw "bucket") prefix:Text="" credentials:AWS_Credential=..Default max_count:Integer=1000 = @@ -126,6 +128,7 @@ get_object bucket key credentials:AWS_Credential=AWS_Credential.Default delimite `AWS_SDK_Error` will be raised. - If the bucket does not exist, an `S3_Bucket_Not_Found` error is thrown. - If the object does not exist, an `S3_Key_Not_Found` error is thrown. +@bucket (Text_Input display=..Always) @credentials AWS_Credential.default_widget head : Text -> Text -> AWS_Credential -> Dictionary Text Any ! S3_Error head (bucket : Text = Missing_Argument.throw "bucket") key:Text="" credentials:AWS_Credential=..Default = diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso index aab17de496..955ea09f29 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso @@ -82,7 +82,7 @@ from project.System.File_Format import Auto_Detect, File_Format import Standard.Examples example_xls_to_table = Data.read Examples.xls (..Sheet 'Dates') -@path Text_Input +@path (Text_Input display=..Always) @format File_Format.default_widget read : Text | URI | File -> File_Format -> Problem_Behavior -> Any ! File_Error read path=(Missing_Argument.throw "path") format=Auto_Detect (on_problems : Problem_Behavior = ..Report_Warning) = case path of @@ -138,7 +138,7 @@ read path=(Missing_Argument.throw "path") format=Auto_Detect (on_problems : Prob files = Data.list name_filter="*.csv" example_csv_dir_to_table = Data.read_many files -@paths (Vector_Editor item_editor=Text_Input item_default='""') +@paths (Vector_Editor item_editor=Text_Input item_default='""' display=..Always) @format File_Format.default_widget read_many : Many_Files_List -> File_Format -> Return_As -> Problem_Behavior -> Any ! File_Error read_many (paths : Many_Files_List = Missing_Argument.throw "paths") format=Auto_Detect return=..Vector (on_problems : Problem_Behavior = ..Report_Warning) = @@ -170,7 +170,7 @@ read_many (paths : Many_Files_List = Missing_Argument.throw "paths") format=Auto import Standard.Examples example_read = Data.read_text Examples.csv_path -@path Text_Input +@path (Text_Input display=..Always) @encoding Encoding.default_widget read_text : (Text | File) -> Encoding -> Problem_Behavior -> Text read_text path=(Missing_Argument.throw "path") (encoding : Encoding = Encoding.default) (on_problems : Problem_Behavior = ..Report_Warning) = @@ -228,7 +228,7 @@ read_text path=(Missing_Argument.throw "path") (encoding : Encoding = Encoding.d example_list_files = Data.list Examples.data_dir name_filter="**.md" recursive=True -@directory Folder_Browse +@directory (Folder_Browse display=..Always) @name_filter File_Format.name_filter_widget list : Text | File -> Text -> Boolean -> Vector File list (directory:(Text | File)=enso_project.root) (name_filter:Text="") recursive:Boolean=False = diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso index c4336db1bd..d6656aa83b 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso @@ -18,7 +18,7 @@ import project.Runtime.Ref.Ref from project.Data.Boolean import Boolean, False, True from project.Data.Range.Extensions import all from project.Errors.Common import Unsupported_Argument_Types -from project.Metadata import Choice, Widget +from project.Metadata import Choice, Display, Widget polyglot java import java.lang.NullPointerException polyglot java import org.enso.base.CompareException @@ -133,11 +133,10 @@ type Statistic ## PRIVATE Bulk widget for Statistic. - bulk_widget : Widget - bulk_widget = + bulk_widget display:Display=..When_Modified -> Widget = options = ["Count", "Minimum", "Maximum", "Sum", "Product", "Mean", "Variance", "Standard_Deviation", "Skew", "Kurtosis", "Covariance", "Pearson", "Spearman", "R_Squared"].map n-> Choice.Option n ".."+n items = Widget.Single_Choice options - Widget.Vector_Editor items "..Count" + Widget.Vector_Editor items "..Count" display=display ## PRIVATE Gets the order needed to compute a statistic for a moment based statistic. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics/Extensions.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics/Extensions.enso index e87bdaeccd..d47218408c 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics/Extensions.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics/Extensions.enso @@ -18,7 +18,7 @@ Vector.compute self statistic:Statistic=..Count = Arguments: - statistics: Set of statistics to calculate. -@statistics Statistic.bulk_widget +@statistics (Statistic.bulk_widget display=..Always) Vector.compute_bulk : Vector Statistic -> Vector Any Vector.compute_bulk self statistics:Vector=[..Count, ..Sum] = Statistic.compute_bulk self statistics @@ -41,7 +41,7 @@ Vector.running self statistic:Statistic=..Count = Arguments: - statistics: Set of statistics to calculate. -@statistics Statistic.bulk_widget +@statistics (Statistic.bulk_widget display=..Always) Vector.running_bulk : Vector Statistic -> Vector Any Vector.running_bulk self (statistics:(Vector Statistic)=[..Count, ..Sum]) = Statistic.running_bulk self statistics diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Credentials.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Credentials.enso index 16fbf40e37..877a05ea84 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Credentials.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Credentials.enso @@ -1,4 +1,5 @@ from Standard.Base import all +import Standard.Base.Errors.Common.Missing_Argument import Standard.Base.Metadata.Display import Standard.Base.Metadata.Widget from Standard.Base.Metadata.Choice import Option @@ -7,9 +8,11 @@ from Standard.Base.Widget_Helpers import make_text_secret_selector type Credentials ## Simple username and password type. - @username make_text_secret_selector - @password make_text_secret_selector - Username_And_Password username:(Text|Enso_Secret) password:(Text|Enso_Secret) + @username (make_text_secret_selector display=..Always) + @password (make_text_secret_selector display=..Always) + Username_And_Password + username:(Text|Enso_Secret)=(Missing_Argument.throw "username") + password:(Text|Enso_Secret)=(Missing_Argument.throw "password") ## PRIVATE Override `to_text` to mask the password field. diff --git a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics.enso b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics.enso index b869072c5c..1ab6b3adb5 100644 --- a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics.enso +++ b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics.enso @@ -1,7 +1,7 @@ from Standard.Base import all import Standard.Base.Data.Array_Proxy.Array_Proxy import Standard.Base.Errors.Common.Missing_Argument -from Standard.Base.Metadata import make_single_choice, Widget +from Standard.Base.Metadata import Display, make_single_choice, Widget from Standard.Base.Metadata.Choice import Option from Standard.Base.Metadata.Widget import Single_Choice, Text_Input, Vector_Editor @@ -34,14 +34,14 @@ type Google_Analytics - credentials: The Google credentials to use. Default is to use the Google Application Default Credentials in the environment variables. See https://cloud.google.com/docs/authentication/application-default-credentials + @credentials (Google_Credential.default_widget display=..Always) @property Google_Analytics_Property.default_widget @dimensions _make_dimensions_vector_selector @metrics _make_metrics_vector_selector @start_date _make_start_date_widget @end_date (Date.default_widget include_today=True) - @credentials Google_Credential.default_widget - read : Google_Analytics_Property -> (Vector Text) -> (Vector Text) -> Date -> Date -> Google_Credential -> Table - read property:Google_Analytics_Property=(Missing_Argument.throw "property") dimensions:Vector=['country'] metrics:Vector=['activeUsers'] start_date:Date=(Date.today.previous ..Year) end_date:Date=Date.today credentials:Google_Credential=..Default -> Table = + read : Google_Credential -> Google_Analytics_Property -> (Vector Text) -> (Vector Text) -> Date -> Date -> Table + read credentials:Google_Credential=(Missing_Argument.throw "credentials") property:Google_Analytics_Property=(Missing_Argument.throw "property") dimensions:Vector=['country'] metrics:Vector=['activeUsers'] start_date:Date=(Date.today.previous ..Year) end_date:Date=Date.today -> Table = case credentials of Google_Credential.Sample -> _read_sample_data dimensions metrics start_date end_date _ -> @@ -60,7 +60,7 @@ type Google_Analytics See https://cloud.google.com/docs/authentication/application-default-credentials - limit: The maximum number of accounts to read. Default is 1000. - include_deleted: Whether to include deleted accounts. Default is false. - @credentials Google_Credential.default_widget + @credentials (Google_Credential.default_widget display=..Always) @limit Rows_To_Read.default_widget list_accounts : Google_Credential -> Rows_To_Read -> Boolean -> Vector list_accounts credentials:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False -> Vector = @@ -82,11 +82,11 @@ type Google_Analytics See https://cloud.google.com/docs/authentication/application-default-credentials - limit: The maximum number of accounts to read. Default is 1000. - include_deleted: Whether to include deleted accounts. Default is false. - @account Google_Analytics_Account_Filter.default_widget @credentials Google_Credential.default_widget + @account Google_Analytics_Account_Filter.default_widget @limit Rows_To_Read.default_widget - list_properties : Google_Analytics_Account_Filter -> Google_Credential -> Rows_To_Read -> Boolean -> Vector - list_properties account:Google_Analytics_Account_Filter=..All_Accounts credentials:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False -> Vector = + list_properties : Google_Credential -> Google_Analytics_Account_Filter -> Rows_To_Read -> Boolean -> Vector + list_properties credentials:Google_Credential=..Default account:Google_Analytics_Account_Filter=..All_Accounts (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False -> Vector = java_credentials = credentials.as_java to_read = limit.rows_to_read.if_nothing 0 filter = account.as_java @@ -103,10 +103,10 @@ type Google_Analytics - credentials: The Google credentials to use. Default is to use the Google Application Default Credentials in the environment variables. See https://cloud.google.com/docs/authentication/application-default-credentials + @credentials (Google_Credential.default_widget display=..Always) @property Google_Analytics_Property.default_widget - @credentials Google_Credential.default_widget - list_metrics : Google_Analytics_Property -> Google_Credential -> Vector - list_metrics property:Google_Analytics_Property=(Missing_Argument.throw "property") credentials:Google_Credential=..Default -> Vector = + list_metrics : Google_Credential -> Google_Analytics_Property -> Vector + list_metrics credentials:Google_Credential=(Missing_Argument.throw "credentials") property:Google_Analytics_Property=(Missing_Argument.throw "property") -> Vector = java_credentials = credentials.as_java array = _handle_google_error <| GoogleAnalyticsReader.listMetrics java_credentials property.java_record array.if_not_error <| array.map record-> Google_Analytics_Field.Metric record @@ -119,35 +119,36 @@ type Google_Analytics - credentials: The Google credentials to use. Default is to use the Google Application Default Credentials in the environment variables. See https://cloud.google.com/docs/authentication/application-default-credentials + @credentials (Google_Credential.default_widget display=..Always) @property Google_Analytics_Property.default_widget - @credentials Google_Credential.default_widget - list_dimensions : Google_Analytics_Property -> Google_Credential -> Vector - list_dimensions property:Google_Analytics_Property=(Missing_Argument.throw "property") credentials:Google_Credential=..Default -> Vector = + list_dimensions : Google_Credential -> Google_Analytics_Property -> Vector + list_dimensions credentials:Google_Credential=(Missing_Argument.throw "credentials") property:Google_Analytics_Property=(Missing_Argument.throw "property") -> Vector = java_credentials = credentials.as_java array = _handle_google_error <| GoogleAnalyticsReader.listDimensions java_credentials property.java_record array.if_not_error <| array.map record-> Google_Analytics_Field.Dimension record -## PRIVATE -private _make_metrics_vector_selector self_arg cache -> Widget = - _ = self_arg - items = Panic.catch Any handler=p->[p.payload.to_display_text] <| - property = cache.if_not_nothing <| cache "property" - property.if_not_nothing <| - credentials = cache.if_not_nothing <| cache "credentials" - Google_Analytics.list_metrics property credentials . map f-> Option (f.apiName + " (" + f.category + ")") f.apiName.pretty - item_editor = make_single_choice (items.if_nothing ['activeUsers', 'bounceRate', 'conversions', 'newUsers', 'sessionsPerUser', 'userConversionRate']) - Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=..Always ## PRIVATE -private _make_dimensions_vector_selector self_arg cache -> Widget = +private _make_metrics_vector_selector self_arg cache display:Display=..Always -> Widget = _ = self_arg items = Panic.catch Any handler=p->[p.payload.to_display_text] <| property = cache.if_not_nothing <| cache "property" property.if_not_nothing <| credentials = cache.if_not_nothing <| cache "credentials" - Google_Analytics.list_dimensions property credentials . map f-> Option (f.api_name + " (" + f.category + ")") f.api_name.pretty + Google_Analytics.list_metrics (credentials.if_nothing Google_Credential.Default) property . map f-> Option (f.api_name + " (" + f.category + ")") f.api_name.pretty + item_editor = make_single_choice (items.if_nothing ['activeUsers', 'bounceRate', 'conversions', 'newUsers', 'sessionsPerUser', 'userConversionRate']) + Widget.Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=display + +## PRIVATE +private _make_dimensions_vector_selector self_arg cache display:Display=..Always -> Widget = + _ = self_arg + items = Panic.catch Any handler=p->[p.payload.to_display_text] <| + property = cache.if_not_nothing <| cache "property" + property.if_not_nothing <| + credentials = cache.if_not_nothing <| cache "credentials" + Google_Analytics.list_dimensions (credentials.if_nothing Google_Credential.Default) property . map f-> Option (f.api_name + " (" + f.category + ")") f.api_name.pretty item_editor = make_single_choice (items.if_nothing ['country', 'year', 'month', 'date', 'userAgeBracket', 'userGender']) - Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=..Always + Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=display ## PRIVATE private _make_start_date_widget -> Widget = diff --git a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Account.enso b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Account.enso index 7ff50fb9cd..780f2bf606 100644 --- a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Account.enso +++ b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Account.enso @@ -42,7 +42,8 @@ type Google_Analytics_Account to_display_text : Text to_display_text self = "GA Account {" + self.name + " (" + self.id + ")}" - ## ICON data_input + ## GROUP Standard.Base.Metadata + ICON data_input List of all properties of the account. Arguments: @@ -53,8 +54,8 @@ type Google_Analytics_Account @credentials Google_Credential.default_widget @limit Rows_To_Read.default_widget properties : Google_Credential -> Rows_To_Read -> Boolean -> Vector - properties self credential:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False = - Google_Analytics.list_properties self credential limit include_deleted + properties self credentials:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False = + Google_Analytics.list_properties credentials self limit include_deleted ## Filter for Google Analytics accounts. type Google_Analytics_Account_Filter diff --git a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Property.enso b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Property.enso index ca8a231b2e..b635802555 100644 --- a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Property.enso +++ b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Analytics_Property.enso @@ -44,32 +44,36 @@ type Google_Analytics_Property to_display_text : Text to_display_text self = self.to_text - ## ICON data_input + ## GROUP Standard.Base.Metadata + ICON data_input List of all metrics of the property. Arguments: - credentials: The Google credentials to use. Default is the default credentials. + @credentials (Google_Credential.default_widget) metrics : Google_Credential -> Vector metrics self credentials:Google_Credential=..Default = - Google_Analytics.list_metrics self credentials + Google_Analytics.list_metrics credentials self - ## ICON data_input + ## GROUP Standard.Base.Metadata + ICON data_input List of all dimensions of the property. Arguments: - credentials: The Google credentials to use. Default is the default credentials. + @credentials (Google_Credential.default_widget) dimensions : Google_Credential -> Vector dimensions self credentials:Google_Credential=..Default = - Google_Analytics.list_dimensions self credentials + Google_Analytics.list_dimensions credentials self ## PRIVATE default_widget self_arg cache display:Display=..Always -> Widget = _ = self_arg Panic.catch Any handler=_->(Widget.Text_Input display=display) <| credentials = cache.if_not_nothing <| cache "credentials" - options = Google_Analytics.list_properties account=..All_Accounts credentials=(credentials.if_nothing Google_Credential.Default) limit=(..First 10) . map p->(Option (p.name + " (" + p.id + ")") p.id.pretty) + options = Google_Analytics.list_properties credentials=(credentials.if_nothing Google_Credential.Default) account=..All_Accounts limit=(..First 10) . map p->(Option (p.name + " (" + p.id + ")") p.id.pretty) make_single_choice options display=display ## PRIVATE diff --git a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Credential.enso b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Credential.enso index 571b3f1735..04efb0419d 100644 --- a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Credential.enso +++ b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Google_Credential.enso @@ -1,5 +1,6 @@ from Standard.Base import all import Standard.Base.Errors.Common.Missing_Argument +import Standard.Base.Runtime.Context from Standard.Base.Metadata import Choice, Display, make_single_choice, Widget from Standard.Base.Metadata.Choice import Option @@ -14,25 +15,31 @@ type Google_Credential Arguments: - file: Path to the json credentials file or `Nothing` for the default. @file (make_single_choice [Choice.Option "File" "File.new", Choice.Option "Default" "Nothing"]) - new : File | Nothing -> Google_Credential - new file:(File | Nothing)=Nothing = case file of + new : Enso_File | File | Nothing -> Google_Credential + new file:(Enso_File | File | Nothing)=Nothing = case file of + _ : Enso_File -> Google_Credential.from file _ : File -> Google_Credential.From_File file Nothing -> Google_Credential.Default + ## PRIVATE + ICON key + Creates a Google credential either from the default environment variables. + default -> Google_Credential = Google_Credential.Default + ## ICON key Access using a json credentials file downloaded from your Google account. Arguments: - file: Path to the json credentials file. - From_File file:File=(Missing_Argument.throw "file") + private From_File file:File=(Missing_Argument.throw "file") ## ICON key Access using the defaults provided by the environment variables. - Default + private Default ## ICON key Feeding this into supporting components will give sample data for that component. - Sample + private Sample ## PRIVATE Gets the Java version of the credentials. @@ -46,10 +53,18 @@ type Google_Credential ## PRIVATE default_widget display:Display=..When_Modified -> Widget = - make_single_choice [Option "File" "..From_File", Option "Default" "..Default"] display=display + make_single_choice [Option "File" "File.new", Option "Default" "Google_Credential.default"] display=display + +## PRIVATE + To enable cloud file to work as a credential, need to localise it. +Google_Credential.from (that:Enso_File) = + tmp_file = File.create_temporary_file "gccloud" ".json" + json = that.read_text + Context.Output.with_enabled <| json.write tmp_file + Google_Credential.from tmp_file ## PRIVATE Google_Credential.from (that:File) = Google_Credential.From_File that ## PRIVATE -Google_Credential.from (that:Text) = Google_Credential.From_File (File.new that) +Google_Credential.from (that:Text) = Google_Credential.from (File.new that) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso index 478a0ffd91..7a96f752b8 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso @@ -104,8 +104,8 @@ type Table Arguments: - columns: A set of either Column objects or pairs of name and data to - construct a column from from. If passing name and data, the items can - be passed as a Vector, Range or a Date_Range. + construct a column from. If passing name and data, the items can be + passed as a Vector, Range or a Date_Range. Returns: - A Table of all of the input data. @@ -198,8 +198,8 @@ type Table Arguments: - columns: A set of either Column objects or set of name, data and - optionally type to construct a column from from. If the data is passed - as Vector Text then it will be parsed into the specified type (defaults + optionally type to construct a column from. If the data is passed as + Vector Text then it will be parsed into the specified type (defaults to auto detect). Returns: @@ -225,11 +225,11 @@ type Table resolved_columns = columns.map c-> case c of _ : Column -> c _ : Vector -> if c.length < 2 || (c.first . is_a Text).not then throw_bad_column else - raw_column = Column.from_vector c.first (c.at 1) + raw_column = Column.from_vector c.first c.second target_type = c.get 2 Auto if target_type != Auto && (target_type.is_a Value_Type).not then throw_bad_column else case raw_column.value_type.is_text of - True -> if target_type != Auto && target_type.is_text then raw_column.cast target_type else raw_column.parse target_type + True -> if target_type.is_a Value_Type && target_type.is_text then raw_column.cast target_type else raw_column.parse target_type False -> if target_type == Auto then raw_column else raw_column.cast target_type _ -> throw_bad_column resolved_columns.if_not_error <| Table.new resolved_columns diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso index 68b29f2a4e..32619b29ef 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso @@ -197,11 +197,7 @@ Table.lookup_ignore_case self name = Guides the visualization system to display the most suitable graphical representation for this table. Table.default_visualization : Id -Table.default_visualization self = - cols = self.columns.map .name . map name-> name.to_case Case.Lower - if cols.contains "latitude" && cols.contains "longitude" then Id.geo_map else - if cols.contains "x" && cols.contains "y" then Id.scatter_plot else - Id.table +Table.default_visualization self = Id.table ## PRIVATE diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso index d909ba4bf0..5fc26840f5 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso @@ -16,12 +16,12 @@ import project.Helpers Prepares a table or column for visualization. Arguments: - - x: The table to prepare for visualization. + - y: The table to prepare for visualization. - max_rows: The maximum number of rows to display. In case of Database backed data, it materializes a fragment of the data. prepare_visualization : Any -> Integer -> Text -prepare_visualization y max_rows=1000 = +prepare_visualization y max_rows=1000 = if y.is_error then (make_json_for_error y.catch).to_text else x = Warning.set y [] result = case x of @@ -63,10 +63,17 @@ max_columns = 250 whitespace_count : Column -> Integer | Nothing whitespace_count col = find_whitespace col = - filtered = col.to_vector.filter (c-> c.is_a Text && (c.first.is_whitespace || c.last.is_whitespace)) + filtered = col.to_vector.filter (c-> c.is_a Text && c.is_empty.not && (c.first.is_whitespace || c.last.is_whitespace)) filtered.length if (col.value_type == Value_Type.Mixed || col.value_type.is_text) then find_whitespace col else Nothing +## PRIVATE + Render Error to JSON +make_json_for_error : Any -> JS_Object +make_json_for_error error = + pairs = [["error", error.to_display_text]] + JS_Object.from_pairs pairs + ## PRIVATE Render Vector to JSON make_json_for_vector : Vector -> Integer -> JS_Object diff --git a/test/Visualization_Tests/src/Id_Spec.enso b/test/Visualization_Tests/src/Id_Spec.enso index 42a70f6415..0a37af361a 100644 --- a/test/Visualization_Tests/src/Id_Spec.enso +++ b/test/Visualization_Tests/src/Id_Spec.enso @@ -49,12 +49,12 @@ add_specs suite_builder = suite_builder.group "Serializable Visualization Identi c_1_1 = ['x', [1, 2, 3]] c_1_2 = ['Y', [5.3, 56.2, 6.3]] t_1 = Table.new [c_1_1, c_1_2] - t_1.default_visualization.should_equal Visualization.Id.scatter_plot + t_1.default_visualization.should_equal Visualization.Id.table c_2_1 = ['LaTituDe', [5,3,2]] c_2_2 = ['longitude', [6,7,8]] t_2 = Table.new [c_2_1, c_2_2] - t_2.default_visualization.should_equal Visualization.Id.geo_map + t_2.default_visualization.should_equal Visualization.Id.table c_3_1 = ['latitude', [5,2,5]] c_3_2 = ['Y', [2,4,2]] From 9a49a02e3f458e7c9f87d38224b62b688bbc9b24 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 18 Nov 2024 23:44:54 +0100 Subject: [PATCH 02/15] --jvm tries to find Java executable system-wide. (#11500) Fixes `--jvm` option, given to the native image. This was failing on my machine, because when given `--jvm` option, the runner was trying to find the `java` executable from the distribution manager's runtime (on my system located in `~/.local/share/enso/runtime`) and it used the first runtime found. But the first runtime on my system is JDK 17. The `--jvm` option now tries to: - Find a JDK from the distribution manager that has the same version as the JDK used for building the engine. - If there is not an exact version match, it tries to find a runtime from distribution manager that is *newer*. - If none, fallback to system-wide search - System-wide search tries to find `java` from `$JAVA_HOME` and from `$PATH`. But this is just a fallback. # Important Notes - Added test to Engine CI jobs that pass `--jvm` argument to a native image of engine-runner - ea3af5ffbca6dc439690142251426b4c167bca98 - `runtime-version-manager` sbt project migrated to a JPMS module - `engine-runner` now depends on `runtime-version-manager`. - Removed unnecessary stuff in `runtime-version-manager` dealing with outdated `gu` Graal Updater utility. - Extracted [GraalVersionManager](https://github.com/enso-org/enso/blob/1455b025cb8e5141409ea96b75577e8884265a70/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java) from [RuntimeVersionManager](https://github.com/enso-org/enso/blob/d2e8994700fd36228f7873f040668013e643190a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala) --- build.sbt | 29 ++- build/build/src/engine/context.rs | 21 +- distribution/launcher/THIRD-PARTY/NOTICE | 15 -- .../NOTICES | 11 - .../NOTICES | 1 - .../NOTICES | 7 - .../distribution/DefaultManagers.scala | 7 +- engine/runner/src/main/java/module-info.java | 1 + .../main/java/org/enso/runner/JavaFinder.java | 110 ++++++++++ .../src/main/java/org/enso/runner/Main.java | 19 +- .../DefaultDistributionConfiguration.scala | 16 +- .../TestDistributionConfiguration.scala | 13 +- .../test/NoopComponentUpdater.scala | 20 -- .../test/NoopComponentUpdaterFactory.scala | 15 -- .../test/RuntimeVersionManagerTest.scala | 7 +- .../locking/ConcurrencyTest.scala | 7 +- .../src/main/java/module-info.java | 22 ++ .../components/GraalVersionManager.java | 140 ++++++++++++ .../runtimeversionmanager/package-info.java | 1 - .../runtimeversionmanager/cli/Arguments.scala | 9 - .../components/GraalVMComponent.scala | 11 - .../GraalVMComponentConfiguration.scala | 89 -------- .../components/GraalVMComponentUpdater.scala | 180 ---------------- .../components/GraalVMVersion.scala | 41 +++- .../RuntimeComponentConfiguration.scala | 19 -- .../components/RuntimeComponentUpdater.scala | 19 -- .../RuntimeComponentUpdaterFactory.scala | 30 --- .../components/RuntimeVersionManager.scala | 201 ++---------------- .../UnchainedGraalVMComponentUpdater.scala | 26 --- .../GraalVMComponentConfigurationSpec.scala | 106 --------- .../GraalVMComponentParserSpec.scala | 57 ----- .../components/GraalVMVersionSpec.scala | 40 ++++ .../java/org/enso/semver/VersionsTest.java | 2 + .../java/org/enso/version/BuildVersion.java | 13 ++ project/BuildInfo.scala | 6 + .../copyright-ignore | 8 - .../copyright-keep | 6 - .../copyright-ignore | 6 - .../copyright-keep | 1 - .../copyright-ignore | 2 - .../copyright-keep | 4 - tools/legal-review/launcher/report-state | 4 +- 42 files changed, 453 insertions(+), 889 deletions(-) delete mode 100644 distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http-core_2.13-10.2.10/NOTICES delete mode 100644 distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http_2.13-10.2.10/NOTICES delete mode 100644 distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-parsing_2.13-10.2.10/NOTICES create mode 100644 engine/runner/src/main/java/org/enso/runner/JavaFinder.java delete mode 100644 lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdater.scala delete mode 100644 lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdaterFactory.scala create mode 100644 lib/scala/runtime-version-manager/src/main/java/module-info.java create mode 100644 lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java delete mode 100644 lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/package-info.java delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponent.scala delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfiguration.scala delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentUpdater.scala delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentConfiguration.scala delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdater.scala delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdaterFactory.scala delete mode 100644 lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/UnchainedGraalVMComponentUpdater.scala delete mode 100644 lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfigurationSpec.scala delete mode 100644 lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentParserSpec.scala create mode 100644 lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMVersionSpec.scala delete mode 100644 tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-ignore delete mode 100644 tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-keep delete mode 100644 tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-ignore delete mode 100644 tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-keep delete mode 100644 tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-ignore delete mode 100644 tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-keep diff --git a/build.sbt b/build.sbt index 3a3b909918..17d5a6e7b4 100644 --- a/build.sbt +++ b/build.sbt @@ -721,6 +721,7 @@ lazy val componentModulesPaths = (`runtime-instrument-runtime-server` / Compile / exportedModuleBin).value, (`runtime-language-arrow` / Compile / exportedModuleBin).value, (`runtime-language-epb` / Compile / exportedModuleBin).value, + (`runtime-version-manager` / Compile / exportedModuleBin).value, (`persistance` / Compile / exportedModuleBin).value, (`cli` / Compile / exportedModuleBin).value, (`json-rpc-server` / Compile / exportedModuleBin).value, @@ -1613,7 +1614,8 @@ lazy val `version-output` = (project in file("lib/scala/version-output")) defaultDevEnsoVersion = defaultDevEnsoVersion, ensoVersion = ensoVersion, scalacVersion = scalacVersion, - graalVersion = graalVersion, + graalVersion = graalMavenPackagesVersion, + javaVersion = graalVersion, currentEdition = currentEdition ) }.taskValue @@ -3525,6 +3527,7 @@ lazy val `engine-runner` = project (`pkg` / Compile / exportedModule).value, (`engine-runner-common` / Compile / exportedModule).value, (`runtime-parser` / Compile / exportedModule).value, + (`runtime-version-manager` / Compile / exportedModule).value, (`version-output` / Compile / exportedModule).value, (`engine-common` / Compile / exportedModule).value, (`polyglot-api` / Compile / exportedModule).value, @@ -3700,6 +3703,7 @@ lazy val `engine-runner` = project .dependsOn(`distribution-manager`) .dependsOn(`edition-updater`) .dependsOn(`runtime-parser`) + .dependsOn(`runtime-version-manager`) .dependsOn(`logging-service`) .dependsOn(`logging-service-logback` % Runtime) .dependsOn(`engine-runner-common`) @@ -4337,15 +4341,34 @@ lazy val `connected-lock-manager-server` = project lazy val `runtime-version-manager` = project .in(file("lib/scala/runtime-version-manager")) + .enablePlugins(JPMSPlugin) .configs(Test) .settings( frgaalJavaCompilerSetting, + scalaModuleDependencySetting, + mixedJavaScalaProjectSetting, resolvers += Resolver.bintrayRepo("gn0s1s", "releases"), libraryDependencies ++= Seq( "com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion, "org.apache.commons" % "commons-compress" % commonsCompressVersion, - "org.scalatest" %% "scalatest" % scalatestVersion % Test, - akkaHttp + "org.scalatest" %% "scalatest" % scalatestVersion % Test + ), + Compile / moduleDependencies ++= Seq( + "org.apache.commons" % "commons-compress" % commonsCompressVersion, + "org.slf4j" % "slf4j-api" % slf4jVersion + ), + Compile / internalModuleDependencies := Seq( + (`cli` / Compile / exportedModule).value, + (`distribution-manager` / Compile / exportedModule).value, + (`downloader` / Compile / exportedModule).value, + (`editions` / Compile / exportedModule).value, + (`edition-updater` / Compile / exportedModule).value, + (`logging-utils` / Compile / exportedModule).value, + (`pkg` / Compile / exportedModule).value, + (`semver` / Compile / exportedModule).value, + (`scala-libs-wrapper` / Compile / exportedModule).value, + (`scala-yaml` / Compile / exportedModule).value, + (`version-output` / Compile / exportedModule).value ) ) .dependsOn(pkg) diff --git a/build/build/src/engine/context.rs b/build/build/src/engine/context.rs index 42328320a7..8b4b9f65b4 100644 --- a/build/build/src/engine/context.rs +++ b/build/build/src/engine/context.rs @@ -664,6 +664,7 @@ pub async fn runner_sanity_test( .bin .join("enso") .with_executable_extension(); + let test_base = Command::new(&enso) .args(["--run", repo_root.test.join("Base_Tests").as_str()]) .set_env(ENSO_DATA_DIRECTORY, engine_package)? @@ -686,7 +687,25 @@ pub async fn runner_sanity_test( .run_ok() .await; - test_base.and(test_internal_base).and(test_geo) + let all_cmds = test_base.and(test_internal_base).and(test_geo); + + // The following test does not actually run anything, it just checks if the engine + // can accept `--jvm` argument and evaluates something. + if TARGET_OS != OS::Windows { + let test_jvm_arg = Command::new(&enso) + .args([ + "--jvm", + "--run", + repo_root.test.join("Base_Tests").as_str(), + "__NON_EXISTING_TEST__", + ]) + .set_env(ENSO_DATA_DIRECTORY, engine_package)? + .run_ok() + .await; + all_cmds.and(test_jvm_arg) + } else { + all_cmds + } } else { Ok(()) } diff --git a/distribution/launcher/THIRD-PARTY/NOTICE b/distribution/launcher/THIRD-PARTY/NOTICE index 9f5326ae53..b09d657a90 100644 --- a/distribution/launcher/THIRD-PARTY/NOTICE +++ b/distribution/launcher/THIRD-PARTY/NOTICE @@ -36,21 +36,6 @@ The license file can be found at `licenses/APACHE2.0`. Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-actor_2.13-2.6.20`. -'akka-http-core_2.13', licensed under the Apache-2.0, is distributed with the launcher. -The license file can be found at `licenses/APACHE2.0`. -Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-http-core_2.13-10.2.10`. - - -'akka-http_2.13', licensed under the Apache-2.0, is distributed with the launcher. -The license file can be found at `licenses/APACHE2.0`. -Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-http_2.13-10.2.10`. - - -'akka-parsing_2.13', licensed under the Apache-2.0, is distributed with the launcher. -The license file can be found at `licenses/APACHE2.0`. -Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-parsing_2.13-10.2.10`. - - 'akka-slf4j_2.13', licensed under the Apache-2.0, is distributed with the launcher. The license file can be found at `licenses/APACHE2.0`. Copyright notices related to this dependency can be found in the directory `com.typesafe.akka.akka-slf4j_2.13-2.6.20`. diff --git a/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http-core_2.13-10.2.10/NOTICES b/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http-core_2.13-10.2.10/NOTICES deleted file mode 100644 index 03925592b6..0000000000 --- a/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http-core_2.13-10.2.10/NOTICES +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (C) 2008-2017 Bjoern Hoehrmann - -Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev - -Copyright (C) 2009-2022 Lightbend Inc. - -Copyright 2011 Mark Harrah, Eugene Yokota - -Copyright 2014 Twitter, Inc. - -Copyright 2015 Heiko Seeberger diff --git a/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http_2.13-10.2.10/NOTICES b/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http_2.13-10.2.10/NOTICES deleted file mode 100644 index e25cd2d998..0000000000 --- a/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-http_2.13-10.2.10/NOTICES +++ /dev/null @@ -1 +0,0 @@ -Copyright (C) 2009-2020 Lightbend Inc. diff --git a/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-parsing_2.13-10.2.10/NOTICES b/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-parsing_2.13-10.2.10/NOTICES deleted file mode 100644 index 055c0b3015..0000000000 --- a/distribution/launcher/THIRD-PARTY/com.typesafe.akka.akka-parsing_2.13-10.2.10/NOTICES +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev - -Copyright (C) 2009-2022 Lightbend Inc. - -Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com) - -Copyright (c) 2011-13 Miles Sabin diff --git a/engine/launcher/src/main/scala/org/enso/launcher/distribution/DefaultManagers.scala b/engine/launcher/src/main/scala/org/enso/launcher/distribution/DefaultManagers.scala index d23063c813..8105e3a66d 100644 --- a/engine/launcher/src/main/scala/org/enso/launcher/distribution/DefaultManagers.scala +++ b/engine/launcher/src/main/scala/org/enso/launcher/distribution/DefaultManagers.scala @@ -39,10 +39,6 @@ object DefaultManagers { lazy val temporaryDirectoryManager = TemporaryDirectoryManager(distributionManager, defaultResourceManager) - /** Default [[RuntimeComponentConfiguration]]. */ - lazy val componentConfig: RuntimeComponentConfiguration = - new GraalVMComponentConfiguration - /** Creates a [[RuntimeVersionManager]] that uses the default distribution. */ def runtimeVersionManager( globalCLIOptions: GlobalCLIOptions, @@ -55,12 +51,11 @@ object DefaultManagers { alwaysInstallMissing ), distributionManager, + new GraalVersionManager(distributionManager, LauncherEnvironment), temporaryDirectoryManager, defaultResourceManager, EngineRepository.defaultEngineReleaseProvider, GraalCEReleaseProvider.default, - componentConfig, - RuntimeComponentUpdaterFactory.Default, InstallerKind.Launcher ) } diff --git a/engine/runner/src/main/java/module-info.java b/engine/runner/src/main/java/module-info.java index dd625d9c59..493c5af4ad 100644 --- a/engine/runner/src/main/java/module-info.java +++ b/engine/runner/src/main/java/module-info.java @@ -9,6 +9,7 @@ module org.enso.runner { requires org.enso.logging.config; requires org.enso.logging.utils; requires org.enso.runtime.parser; + requires org.enso.runtime.version.manager; requires org.enso.runner.common; requires org.enso.pkg; requires org.enso.polyglot.api; diff --git a/engine/runner/src/main/java/org/enso/runner/JavaFinder.java b/engine/runner/src/main/java/org/enso/runner/JavaFinder.java new file mode 100644 index 0000000000..44b340e762 --- /dev/null +++ b/engine/runner/src/main/java/org/enso/runner/JavaFinder.java @@ -0,0 +1,110 @@ +package org.enso.runner; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.concurrent.TimeUnit; +import org.enso.distribution.DistributionManager; +import org.enso.distribution.Environment; +import org.enso.runtimeversionmanager.components.GraalRuntime; +import org.enso.runtimeversionmanager.components.GraalVMVersion; +import org.enso.runtimeversionmanager.components.GraalVersionManager; +import org.enso.version.BuildVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Utility class that tries to find installed JDK on the system. */ +final class JavaFinder { + private static final Logger logger = LoggerFactory.getLogger(JavaFinder.class); + + private JavaFinder() {} + + /** + * Tries to find {@code java} executable on the system. If a system-wide JDK is not found, tries + * to find it in the {@link DistributionManager distribution} runtimes. + * + * @return null if cannot be found. Otherwise, returns the absolute path to the executable, or + * simply {@code java} if it is on the {@code PATH}. + */ + static String findJavaExecutable() { + var javaInRuntime = findJavaExecutableInDistributionRuntimes(); + if (javaInRuntime != null) { + return javaInRuntime.toAbsolutePath().toString(); + } + logger.warn("No appropriate JDK found in the distribution runtimes. Trying system-wide JDK."); + var javaHome = System.getenv("JAVA_HOME"); + if (javaHome != null) { + var binDir = Path.of(javaHome).resolve("bin"); + Path javaExe; + if (isOnWindows()) { + javaExe = binDir.resolve("java.exe"); + } else { + javaExe = binDir.resolve("java"); + } + if (javaExe.toFile().exists()) { + logger.warn("Found JDK in JAVA_HOME: {}", javaHome); + return javaExe.toAbsolutePath().toString(); + } + } + logger.warn("No JDK found in JAVA_HOME. Trying java on PATH."); + if (isJavaOnPath()) { + var javaExe = isOnWindows() ? "java.exe" : "java"; + logger.warn("Falling back to java on PATH: {}", javaExe); + return javaExe; + } + logger.warn("No JDK found on PATH. Cannot start the runtime."); + return null; + } + + private static boolean isOnWindows() { + return System.getProperty("os.name").equals("windows"); + } + + /** + * Tries to find {@code java} executable in the distribution runtime with the same version that + * was used for building, or a newer one. + * + * @return null if not found. + */ + private static Path findJavaExecutableInDistributionRuntimes() { + var env = new Environment() {}; + var distributionManager = new DistributionManager(env); + var graalVersionManager = new GraalVersionManager(distributionManager, env); + var versionUsedForBuild = + new GraalVMVersion(BuildVersion.graalVersion(), BuildVersion.javaVersion()); + var runtimeWithExactVersionMatch = graalVersionManager.findGraalRuntime(versionUsedForBuild); + if (runtimeWithExactVersionMatch != null) { + return runtimeWithExactVersionMatch.javaExecutable(); + } + // Try to find newer runtime (JDK). + var newerRuntime = + graalVersionManager.getAllRuntimes().stream() + .sorted(Comparator.comparing(GraalRuntime::version)) + .filter(runtime -> runtime.version().compareTo(versionUsedForBuild) > 0) + .findFirst(); + if (newerRuntime.isPresent()) { + logger.warn( + "Found newer JDK [{}] than the one used for build [{}]", + newerRuntime.get().version(), + versionUsedForBuild); + return newerRuntime.get().javaExecutable(); + } + return null; + } + + private static boolean isJavaOnPath() { + try { + ProcessBuilder processBuilder; + if (isOnWindows()) { + processBuilder = new ProcessBuilder("java.exe", "-h"); + } else { + processBuilder = new ProcessBuilder("java", "-h"); + } + Process process = processBuilder.start(); + boolean exitSucc = process.waitFor(5L, TimeUnit.SECONDS); + return exitSucc; + } catch (IOException | InterruptedException e) { + return false; + } + } +} diff --git a/engine/runner/src/main/java/org/enso/runner/Main.java b/engine/runner/src/main/java/org/enso/runner/Main.java index fd99d8486c..711c424881 100644 --- a/engine/runner/src/main/java/org/enso/runner/Main.java +++ b/engine/runner/src/main/java/org/enso/runner/Main.java @@ -1339,22 +1339,13 @@ public class Main { println(JVM_OPTION + " option has no effect - already running in JVM " + current); } else { var commandAndArgs = new ArrayList(); - JVM_FOUND: if (jvm == null) { - var env = new Environment() {}; - var dm = new DistributionManager(env); - var paths = dm.paths(); - var files = paths.runtimes().toFile().listFiles(); - if (files != null) { - for (var d : files) { - var java = new File(new File(d, "bin"), "java").getAbsoluteFile(); - if (java.exists()) { - commandAndArgs.add(java.getPath()); - break JVM_FOUND; - } - } + var javaExe = JavaFinder.findJavaExecutable(); + if (javaExe == null) { + println("Cannot find java executable"); + throw exitFail(); } - commandAndArgs.add("java"); + commandAndArgs.add(javaExe); } else { commandAndArgs.add(new File(new File(new File(jvm), "bin"), "java").getAbsolutePath()); } diff --git a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/versionmanagement/DefaultDistributionConfiguration.scala b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/versionmanagement/DefaultDistributionConfiguration.scala index b4fd9c79e0..59e4b9b703 100644 --- a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/versionmanagement/DefaultDistributionConfiguration.scala +++ b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/versionmanagement/DefaultDistributionConfiguration.scala @@ -52,12 +52,6 @@ object DefaultDistributionConfiguration lazy val temporaryDirectoryManager = TemporaryDirectoryManager(distributionManager, resourceManager) - lazy val componentConfiguration: RuntimeComponentConfiguration = - new GraalVMComponentConfiguration - - lazy val runtimeComponentUpdaterFactory: RuntimeComponentUpdaterFactory = - RuntimeComponentUpdaterFactory.Default - /** @inheritdoc */ def engineReleaseProvider: ReleaseProvider[EngineRelease] = EngineRepository.defaultEngineReleaseProvider @@ -67,15 +61,15 @@ object DefaultDistributionConfiguration userInterface: RuntimeVersionManagementUserInterface ): RuntimeVersionManager = new RuntimeVersionManager( - environment = this.environment, - userInterface = userInterface, - distributionManager = distributionManager, + environment = this.environment, + userInterface = userInterface, + distributionManager = distributionManager, + graalVersionManager = + new GraalVersionManager(distributionManager, environment), temporaryDirectoryManager = temporaryDirectoryManager, resourceManager = resourceManager, engineReleaseProvider = engineReleaseProvider, runtimeReleaseProvider = GraalCEReleaseProvider.default, - componentConfig = componentConfiguration, - componentUpdaterFactory = runtimeComponentUpdaterFactory, installerKind = InstallerKind.ProjectManager ) diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/TestDistributionConfiguration.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/TestDistributionConfiguration.scala index 5e84b2f0ec..6d3fdb344d 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/TestDistributionConfiguration.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/TestDistributionConfiguration.scala @@ -7,7 +7,7 @@ import org.enso.editions.updater.EditionManager import java.nio.file.Path import org.enso.projectmanager.versionmanagement.DistributionConfiguration import org.enso.runtimeversionmanager.components.{ - GraalVMComponentConfiguration, + GraalVersionManager, InstallerKind, RuntimeVersionManagementUserInterface, RuntimeVersionManager @@ -28,7 +28,6 @@ import org.enso.runtimeversionmanager.releases.{ import org.enso.runtimeversionmanager.runner.{JVMSettings, JavaCommand} import org.enso.runtimeversionmanager.test.{ FakeEnvironment, - NoopComponentUpdaterFactory, TestLocalLockManager } import org.enso.testkit.HasTestDirectory @@ -60,6 +59,9 @@ class TestDistributionConfiguration( lazy val distributionManager = new DistributionManager(environment) + lazy val graalVersionManager = + new GraalVersionManager(distributionManager, environment) + lazy val lockManager = new TestLocalLockManager lazy val resourceManager = new ResourceManager(lockManager) @@ -69,10 +71,6 @@ class TestDistributionConfiguration( lazy val temporaryDirectoryManager = TemporaryDirectoryManager(distributionManager, resourceManager) - lazy val componentConfig = new GraalVMComponentConfiguration - - lazy val componentUpdaterFactory = NoopComponentUpdaterFactory - override def makeRuntimeVersionManager( userInterface: RuntimeVersionManagementUserInterface ): RuntimeVersionManager = new RuntimeVersionManager( @@ -80,11 +78,10 @@ class TestDistributionConfiguration( userInterface = userInterface, distributionManager = distributionManager, temporaryDirectoryManager = temporaryDirectoryManager, + graalVersionManager = graalVersionManager, resourceManager = resourceManager, engineReleaseProvider = engineReleaseProvider, runtimeReleaseProvider = runtimeReleaseProvider, - componentConfig = componentConfig, - componentUpdaterFactory = componentUpdaterFactory, installerKind = InstallerKind.ProjectManager ) diff --git a/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdater.scala b/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdater.scala deleted file mode 100644 index c11f2648df..0000000000 --- a/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdater.scala +++ /dev/null @@ -1,20 +0,0 @@ -package org.enso.runtimeversionmanager.test - -import org.enso.runtimeversionmanager.components.{ - GraalVMComponent, - RuntimeComponentUpdater -} - -import scala.util.Try - -/** Test component updater that does not do anything. */ -object NoopComponentUpdater extends RuntimeComponentUpdater { - - /** @inheritdoc */ - override def list(): Try[Seq[GraalVMComponent]] = - Try(Seq()) - - /** @inheritdoc */ - override def install(components: Seq[GraalVMComponent]): Try[Unit] = - Try(()) -} diff --git a/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdaterFactory.scala b/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdaterFactory.scala deleted file mode 100644 index fd8cee58d1..0000000000 --- a/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/NoopComponentUpdaterFactory.scala +++ /dev/null @@ -1,15 +0,0 @@ -package org.enso.runtimeversionmanager.test - -import org.enso.runtimeversionmanager.components.{ - GraalRuntime, - RuntimeComponentUpdater, - RuntimeComponentUpdaterFactory -} - -/** Test factory creating a noop updater. */ -object NoopComponentUpdaterFactory extends RuntimeComponentUpdaterFactory { - - /** @inheritdoc */ - override def build(runtime: GraalRuntime): RuntimeComponentUpdater = - NoopComponentUpdater -} diff --git a/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/RuntimeVersionManagerTest.scala b/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/RuntimeVersionManagerTest.scala index d50b6e7004..0fb469c2bd 100644 --- a/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/RuntimeVersionManagerTest.scala +++ b/lib/scala/runtime-version-manager-test/src/main/scala/org/enso/runtimeversionmanager/test/RuntimeVersionManagerTest.scala @@ -9,7 +9,7 @@ import org.enso.distribution.{ } import org.enso.pkg.{Config, PackageManager} import org.enso.runtimeversionmanager.components.{ - GraalVMComponentConfiguration, + GraalVersionManager, InstallerKind, RuntimeVersionManagementUserInterface, RuntimeVersionManager @@ -51,22 +51,21 @@ class RuntimeVersionManagerTest ): (DistributionManager, RuntimeVersionManager, Environment) = { val env = fakeInstalledEnvironment(environmentOverrides) val distributionManager = new PortableDistributionManager(env) + val graalVersionManager = new GraalVersionManager(distributionManager, env) val resourceManager = TestLocalResourceManager.create() val temporaryDirectoryManager = TemporaryDirectoryManager(distributionManager, resourceManager) - val componentConfig = new GraalVMComponentConfiguration val runtimeVersionManager = new RuntimeVersionManager( env, userInterface, distributionManager, + graalVersionManager, temporaryDirectoryManager, resourceManager, engineProvider, runtimeProvider, - componentConfig, - NoopComponentUpdaterFactory, installerKind ) diff --git a/lib/scala/runtime-version-manager-test/src/test/scala/org/enso/distribution/locking/ConcurrencyTest.scala b/lib/scala/runtime-version-manager-test/src/test/scala/org/enso/distribution/locking/ConcurrencyTest.scala index aaf01815b0..895515302f 100644 --- a/lib/scala/runtime-version-manager-test/src/test/scala/org/enso/distribution/locking/ConcurrencyTest.scala +++ b/lib/scala/runtime-version-manager-test/src/test/scala/org/enso/distribution/locking/ConcurrencyTest.scala @@ -9,8 +9,8 @@ import org.enso.distribution.{ TemporaryDirectoryManager } import org.enso.runtimeversionmanager.components.{ - GraalVMComponentConfiguration, GraalVMVersion, + GraalVersionManager, InstallerKind, Manifest, RuntimeVersionManager @@ -140,19 +140,18 @@ class ConcurrencyTest } } + val graalVersionManager = new GraalVersionManager(distributionManager, env) val temporaryDirectoryManager = TemporaryDirectoryManager(distributionManager, resourceManager) - val componentConfig = new GraalVMComponentConfiguration val componentsManager = new RuntimeVersionManager( env, TestRuntimeVersionManagementUserInterface.default, distributionManager, + graalVersionManager, temporaryDirectoryManager, resourceManager, engineProvider, runtimeProvider, - componentConfig, - NoopComponentUpdaterFactory, InstallerKind.Launcher ) diff --git a/lib/scala/runtime-version-manager/src/main/java/module-info.java b/lib/scala/runtime-version-manager/src/main/java/module-info.java new file mode 100644 index 0000000000..7aee955efa --- /dev/null +++ b/lib/scala/runtime-version-manager/src/main/java/module-info.java @@ -0,0 +1,22 @@ +module org.enso.runtime.version.manager { + requires scala.library; + requires org.apache.commons.compress; + requires org.slf4j; + requires org.enso.cli; + requires org.enso.distribution; + requires org.enso.downloader; + requires org.enso.editions; + requires org.enso.editions.updater; + requires org.enso.logging.utils; + requires org.enso.pkg; + requires org.enso.semver; + requires org.enso.scala.yaml; + // For com.typesafe.scalalogging.Logger + requires org.enso.scala.wrapper; + requires org.enso.version.output; + + exports org.enso.runtimeversionmanager; + exports org.enso.runtimeversionmanager.cli; + exports org.enso.runtimeversionmanager.components; + exports org.enso.runtimeversionmanager.runner; +} diff --git a/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java b/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java new file mode 100644 index 0000000000..06c385445d --- /dev/null +++ b/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java @@ -0,0 +1,140 @@ +package org.enso.runtimeversionmanager.components; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import org.enso.distribution.DistributionManager; +import org.enso.distribution.Environment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import scala.jdk.javaapi.CollectionConverters; + +/** + * Utility class that finds installed managed runtimes (Graal JDK) from {@link DistributionManager}. + */ +public final class GraalVersionManager { + private final DistributionManager distributionManager; + private final Environment environment; + private static final Logger logger = LoggerFactory.getLogger(GraalVersionManager.class); + + public GraalVersionManager(DistributionManager distributionManager, Environment environment) { + this.distributionManager = distributionManager; + this.environment = environment; + } + + /** + * Get all locally installed runtimes. + * + * @return Possibly empty list. Not null. + */ + public List getAllRuntimes() { + var foundRuntimes = new ArrayList(); + for (var runtimeSearchPath : + CollectionConverters.asJava(distributionManager.paths().runtimeSearchPaths())) { + if (runtimeSearchPath.toFile().isDirectory()) { + var subdirs = runtimeSearchPath.toFile().listFiles(); + assert subdirs != null; + for (var subdir : subdirs) { + var parsedVersion = parseGraalRuntimeVersionString(subdir.getName()); + if (parsedVersion != null) { + var foundRuntime = new GraalRuntime(parsedVersion, subdir.toPath()); + foundRuntime.ensureValid(); + foundRuntimes.add(foundRuntime); + } + } + } else { + logger.warn("Runtime search path `{}` is not a directory", runtimeSearchPath); + } + } + return foundRuntimes; + } + + /** + * Tries to find a GraalVM runtime for the provided engine. + * + *

Returns null if the runtime is missing. + */ + public GraalRuntime findGraalRuntime(Engine engine) { + return findGraalRuntime(engine.manifest().runtimeVersion()); + } + + /** + * Finds an installed GraalVM runtime with the given {@code version}. + * + *

Returns null if that version is not installed. + */ + public GraalRuntime findGraalRuntime(GraalVMVersion version) { + var explicitPathOpt = environment.getEnvPath("ENSO_JVM_PATH"); + if (explicitPathOpt.isDefined()) { + var runtime = new GraalRuntime(version, explicitPathOpt.get()); + runtime.ensureValid(); + logger.debug("Found GraalVM runtime [{}]", runtime); + return runtime; + } + var pathOpt = findGraalRuntimeOnSearchPath(version); + if (pathOpt != null) { + GraalRuntime runtime; + try { + runtime = loadGraalRuntime(pathOpt); + } catch (Exception e) { + throw new UnrecognizedComponentError( + "The runtime " + + version + + "is already installed, but cannot be " + + "loaded due to " + + e.getMessage() + + "." + + "Until the launcher gets an auto-repair " + + "feature, please try reinstalling the runtime by " + + "uninstalling all engines that use it and installing them " + + "again, or manually removing `" + + pathOpt + + "`", + e); + } + logger.debug("Found GraalVM runtime [{}]", runtime); + return runtime; + } + logger.debug("GraalVM runtime [{}] not found", version); + return null; + } + + public GraalRuntime loadGraalRuntime(Path path) throws UnrecognizedComponentError { + logger.debug("Loading Graal runtime [{}]", path); + var name = path.getFileName().toString(); + var version = parseGraalRuntimeVersionString(name); + if (version == null) { + throw new UnrecognizedComponentError("Invalid runtime component name `" + name + "`", null); + } + var runtime = new GraalRuntime(version, path); + runtime.ensureValid(); + return runtime; + } + + private Path findGraalRuntimeOnSearchPath(GraalVMVersion version) { + var name = graalRuntimeNameForVersion(version); + for (var runtimeSearchPath : + CollectionConverters.asJava(distributionManager.paths().runtimeSearchPaths())) { + var path = runtimeSearchPath.resolve(name); + if (path.toFile().exists()) { + return path; + } + } + return null; + } + + private GraalVMVersion parseGraalRuntimeVersionString(String name) { + var pattern = Pattern.compile("graalvm-ce-java(.+)-(.+)"); + var matcher = pattern.matcher(name); + if (matcher.matches()) { + return new GraalVMVersion(matcher.group(2), matcher.group(1)); + } + logger.warn("Unrecognized runtime name `{}`", name); + return null; + } + + private static String graalRuntimeNameForVersion(GraalVMVersion version) { + return "graalvm-ce-java" + version.javaVersion() + "-" + version.graalVersion(); + } +} diff --git a/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/package-info.java b/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/package-info.java deleted file mode 100644 index 2b5d1e7f35..0000000000 --- a/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package org.enso.runtimeversionmanager; diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/cli/Arguments.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/cli/Arguments.scala index a20026002c..2be09b79e6 100644 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/cli/Arguments.scala +++ b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/cli/Arguments.scala @@ -1,6 +1,5 @@ package org.enso.runtimeversionmanager.cli -import akka.http.scaladsl.model.{IllegalUriException, Uri} import org.enso.cli.arguments.{Argument, OptsParseError} import org.enso.logger.LoggerUtils @@ -9,14 +8,6 @@ import java.net.URISyntaxException import org.slf4j.event.Level object Arguments { - implicit val uriAkkaArgument: Argument[Uri] = (string: String) => - try { - Right(Uri(string)) - } catch { - case error: IllegalUriException => - Left(OptsParseError(s"`$string` is not a valid Uri: $error.")) - } - implicit val uriArgument: Argument[URI] = (string: String) => try { Right(URI.create(string)) diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponent.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponent.scala deleted file mode 100644 index 9fa89490d0..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponent.scala +++ /dev/null @@ -1,11 +0,0 @@ -package org.enso.runtimeversionmanager.components - -/** A component of the GraalVM distribution. */ -case class GraalVMComponent(id: String) - -object GraalVMComponent { - - val js: GraalVMComponent = GraalVMComponent("js") - val python: GraalVMComponent = GraalVMComponent("python") - val R: GraalVMComponent = GraalVMComponent("R") -} diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfiguration.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfiguration.scala deleted file mode 100644 index dc821a5518..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfiguration.scala +++ /dev/null @@ -1,89 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import org.enso.cli.OS - -/** Component configuration of the GraalVM distribution. */ -class GraalVMComponentConfiguration extends RuntimeComponentConfiguration { - - import GraalVMComponentConfiguration._ - - /** @inheritdoc */ - override def getRequiredComponents( - version: GraalVMVersion, - os: OS - ): Seq[GraalVMComponent] = { - val optPythonComponent = - if (os.hasPythonSupport) Seq(GraalVMComponent.python) else Seq() - val optRComponent = - if (os.hasRSupport) Seq(GraalVMComponent.R) else Seq() - if (version.isUnchained) { - Seq() - } else { - version.graalVersion match { - case GraalVersions.Major(v) if v >= 23 => - // Since 23.0.0, R is not bundled in the Graal release anymore. - Seq(GraalVMComponent.js) ++ optPythonComponent - case GraalVersions.Major(v) if v >= 22 => - Seq(GraalVMComponent.js) ++ optRComponent ++ optPythonComponent - case GraalVersions.Major(v) - if v > 20 && os.hasSulongSupport && os.hasRSupport => - Seq(GraalVMComponent.R) ++ optPythonComponent - case _ => - Seq() - } - } - } - -} -object GraalVMComponentConfiguration { - - /** OS extensions. */ - implicit private class OSExtensions(os: OS) { - - /** Check if the provided OS supports Sulong runtime. - * - * Sulong is a Graal sub-project, providing an engine for running - * LLVM bitcode on GraalVM. - * - * @return `true` if the OS supports Sulong runtime and `false` otherwise - */ - def hasSulongSupport: Boolean = - os match { - case OS.Linux => true - case OS.MacOS => true - case OS.Windows => false - } - - /** Check if the provided OS supports Python. - * Python is currently not supported in any form on Windows. - * - * @return `true` if the OS supports Python runtime - */ - def hasPythonSupport: Boolean = - os match { - case OS.Windows => false - case _ => true - } - - /** Check if the provided OS supports FastR. - * FastR is currently not supported in any form on Windows. - * - * @return `true` if the OS supports FastR GraalVM component. - */ - def hasRSupport: Boolean = - os match { - case OS.Windows => false - case _ => true - } - } - - private object GraalVersions { - - /** Get the major Graal version number. */ - object Major { - def unapply(version: String): Option[Int] = { - version.takeWhile(_ != '.').toIntOption - } - } - } -} diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentUpdater.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentUpdater.scala deleted file mode 100644 index 9b781e8a5d..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMComponentUpdater.scala +++ /dev/null @@ -1,180 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import java.nio.file.Path -import com.typesafe.scalalogging.Logger - -import scala.sys.process._ -import scala.util.{Failure, Success, Try} - -/** Module that manages components of the GraalVM distribution. - * - * @param runtime the GraalVM runtime - */ -class GraalVMComponentUpdater(runtime: GraalRuntime) - extends RuntimeComponentUpdater { - - import GraalVMComponentUpdater._ - - private val logger = Logger[GraalVMComponentUpdater] - private val gu = runtime.findExecutable("gu") - - /** Path to the GraalVM's updater. - * - * @return path that will be executed to call the updater - */ - protected def updaterExec: Path = gu - - /** List the installed GraalVM components. - * - * @return the list of installed GraalVM components - */ - override def list(): Try[Seq[GraalVMComponent]] = { - val command = Seq("list", "-v") - - logger.trace("{} {}", gu, Properties(gu)) - logger.debug( - "Executing: JAVA_HOME={} GRAALVM_HOME={} {} {}", - runtime.javaHome, - runtime.javaHome, - gu, - command.mkString(" ") - ) - - val executor = new ExponentialBackoffRetry(5, logger) { - override def cmd: String = "list" - override def executeProcess( - logger: ProcessLogger - ): Try[LazyList[String]] = { - val process = Process( - updaterExec.toAbsolutePath.toString +: command, - Some(runtime.javaHome.toFile), - ("JAVA_HOME", runtime.javaHome), - ("GRAALVM_HOME", runtime.javaHome) - ) - Try(process.lazyLines(logger)) - } - } - executor - .execute() - .map(stdout => if (stdout.isEmpty) Seq() else ListOut.parse(stdout)) - } - - /** Install the provided GraalVM components. - * - * @param components the list of components to install - */ - override def install(components: Seq[GraalVMComponent]): Try[Unit] = { - if (components.nonEmpty) { - val command = "install" +: components.map(_.id) - logger.trace("{} {}", gu, Properties(gu)) - logger.debug( - "Executing: JAVA_HOME={} GRRAALVM_HOME={} {} {}", - runtime.javaHome, - runtime.javaHome, - gu, - command.mkString(" ") - ) - val executor = new ExponentialBackoffRetry(5, logger) { - override def cmd: String = "install" - override def executeProcess( - logger: ProcessLogger - ): Try[LazyList[String]] = { - val process = Process( - updaterExec.toAbsolutePath.toString +: command, - Some(runtime.path.toFile), - ("JAVA_HOME", runtime.javaHome), - ("GRAALVM_HOME", runtime.javaHome) - ) - Try(process.lazyLines(logger)) - } - } - executor.execute().map { stdout => - stdout.foreach(logger.trace(_)) - () - } - } else { - Success(()) - } - } - -} -object GraalVMComponentUpdater { - - abstract class ProcessWithRetries(maxRetries: Int, logger: Logger) { - def executeProcess(logger: ProcessLogger): Try[LazyList[String]] - - def cmd: String - - def execute(): Try[List[String]] = execute(0) - - protected def retryWait(retry: Int): Long - - private def execute(retry: Int): Try[List[String]] = { - val errors = scala.collection.mutable.ListBuffer[String]() - val processLogger = ProcessLogger(err => errors.addOne(err)) - executeProcess(processLogger) match { - case Success(stdout) => - Try(stdout.toList).recoverWith({ - case _ if retry < maxRetries => - try { - Thread.sleep(retryWait(retry)) - } catch { - case _: InterruptedException => - } - execute(retry + 1) - }) - case Failure(exception) if retry < maxRetries => - logger.warn("{} failed: {}. Retrying...", cmd, exception.getMessage) - try { - Thread.sleep(retryWait(retry)) - } catch { - case _: InterruptedException => - } - execute(retry + 1) - case Failure(exception) => - errors.foreach(logger.trace("[stderr] {}", _)) - Failure(exception) - } - } - } - - abstract class ExponentialBackoffRetry(maxRetries: Int, logger: Logger) - extends ProcessWithRetries(maxRetries, logger) { - override def retryWait(retry: Int): Long = { - 200 * 2.toLong ^ retry - } - - } - - implicit private def pathToString(path: Path): String = - path.toAbsolutePath.toString - - /** Debug file properties. */ - private case class Properties(path: Path) { - - private val file = path.toFile - - override def toString: String = - s"{ exists=${file.exists()}, " + - s"executable=${file.canExecute} " + - "}" - } - - /** Parser for the `gu list -v` command output. */ - object ListOut { - - private val ID: String = "ID" - private val separator: Char = ':' - - /** Extract the GraalVM components from the gu output. - * - * @param lines the gu output - * @return the list of GraalVM components. - */ - def parse(lines: Seq[String]): Seq[GraalVMComponent] = - lines - .filter(_.startsWith(ID)) - .map(_.dropWhile(_ != separator).drop(1).trim) - .map(GraalVMComponent(_)) - } -} diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMVersion.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMVersion.scala index aa97aa65a3..91e0f2f259 100644 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMVersion.scala +++ b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/GraalVMVersion.scala @@ -11,7 +11,8 @@ import org.enso.semver.SemVer * Can be specified either as a single integer or as a * semantic version */ -case class GraalVMVersion(graalVersion: String, javaVersion: String) { +case class GraalVMVersion(graalVersion: String, javaVersion: String) + extends Comparable[GraalVMVersion] { require(GraalVMVersion.isCorrectVersionFormat(graalVersion)) require(GraalVMVersion.isCorrectVersionFormat(javaVersion)) @@ -29,15 +30,35 @@ case class GraalVMVersion(graalVersion: String, javaVersion: String) { } } - /** The GraalVM distribution policy changed a lot since GraalVM 23.1.0 for JDK 21. - * Most of the components for the newest GraalVM distributions are distributed as - * artifacts from the Maven central. This mens there is no longer `gu` tool. - * - * @see https://medium.com/graalvm/truffle-unchained-13887b77b62c - * @return true if this version is associated with Truffle unchained. - */ - def isUnchained: Boolean = { - javaMajorVersion >= 21 && graalMajorVersion >= 23 + override def compareTo(other: GraalVMVersion): Int = { + val javaSemVer = SemVer.parse(javaVersion) + val otherJavaSemVer = SemVer.parse(other.javaVersion) + if (javaSemVer.isSuccess && otherJavaSemVer.isSuccess) { + val comp = javaSemVer.get.compareTo(otherJavaSemVer.get) + if (comp != 0) { + return comp + } + } + + val graalSemVer = SemVer.parse(graalVersion) + val otherGraalSemVer = SemVer.parse(other.graalVersion) + if (graalSemVer.isSuccess && otherGraalSemVer.isSuccess) { + val comp = graalSemVer.get.compareTo(otherGraalSemVer.get) + if (comp != 0) { + return comp + } + } + + val javaMajorComp = javaMajorVersion.compareTo(other.javaMajorVersion) + if (javaMajorComp != 0) { + return javaMajorComp + } + val graalMajorComp = graalMajorVersion.compareTo(other.graalMajorVersion) + if (graalMajorComp != 0) { + return graalMajorComp + } + + 0 } } diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentConfiguration.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentConfiguration.scala deleted file mode 100644 index f57cd56edb..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentConfiguration.scala +++ /dev/null @@ -1,19 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import org.enso.cli.OS - -/** Provides configuration of the runtime components. */ -trait RuntimeComponentConfiguration { - - /** Return the list of components required for the provided version of - * the runtime installed on the provided OS. - * - * @param version the runtime version - * @param os the operating system - * @return the list of required components - */ - def getRequiredComponents( - version: GraalVMVersion, - os: OS - ): Seq[GraalVMComponent] -} diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdater.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdater.scala deleted file mode 100644 index 2d3636ebf1..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdater.scala +++ /dev/null @@ -1,19 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import scala.util.Try - -/** Module that manages components of the runtime distribution. */ -trait RuntimeComponentUpdater { - - /** List the installed runtime components. - * - * @return the list of installed runtime components - */ - def list(): Try[Seq[GraalVMComponent]] - - /** Install the provided runtime components. - * - * @param components the list of components to install - */ - def install(components: Seq[GraalVMComponent]): Try[Unit] -} diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdaterFactory.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdaterFactory.scala deleted file mode 100644 index 7cfd192f5b..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeComponentUpdaterFactory.scala +++ /dev/null @@ -1,30 +0,0 @@ -package org.enso.runtimeversionmanager.components - -/** The factory that creates a runtime component updater. */ -trait RuntimeComponentUpdaterFactory { - - /** Create a runtime component updater. - * - * @param runtime the GraalVM runtime - * @return new instance of the runtime component updater - */ - def build(runtime: GraalRuntime): RuntimeComponentUpdater -} - -object RuntimeComponentUpdaterFactory { - - /** The default runtime component updater factory creating an instance of - * [[GraalVMComponentUpdater]]. - */ - object Default extends RuntimeComponentUpdaterFactory { - - /** @inheritdoc */ - override def build(runtime: GraalRuntime): RuntimeComponentUpdater = { - if (runtime.version.isUnchained) { - new UnchainedGraalVMComponentUpdater() - } else { - new GraalVMComponentUpdater(runtime) - } - } - } -} diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala index 0a2fba8426..134c83c637 100644 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala +++ b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala @@ -3,7 +3,6 @@ package org.enso.runtimeversionmanager.components import java.nio.file.{Files, Path, StandardOpenOption} import com.typesafe.scalalogging.Logger import org.enso.semver.SemVer -import org.enso.cli.OS import org.enso.distribution.{ DistributionManager, Environment, @@ -13,7 +12,6 @@ import org.enso.distribution.{ import org.enso.distribution.locking.{LockType, ResourceManager} import org.enso.runtimeversionmanager.CurrentVersion import org.enso.distribution.FileSystem.PathSyntax -import org.enso.logger.masking.MaskedPath import org.enso.downloader.archive.Archive import org.enso.runtimeversionmanager.locking.Resources import org.enso.runtimeversionmanager.releases.ReleaseProvider @@ -32,79 +30,36 @@ import scala.util.{Failure, Success, Try, Using} * @param userInterface a [[RuntimeVersionManagementUserInterface]] instance * that specifies how to handle user interactions * (displaying progress and handling corner cases) - * @param distributionManager the [[DistributionManager]] to use * @param engineReleaseProvider the provider of engine releases * @param runtimeReleaseProvider the provider of runtime releases - * @param componentConfig the runtime component configuration - * @param componentUpdaterFactory the runtime component updater factory */ class RuntimeVersionManager( environment: Environment, userInterface: RuntimeVersionManagementUserInterface, distributionManager: DistributionManager, + graalVersionManager: GraalVersionManager, temporaryDirectoryManager: TemporaryDirectoryManager, resourceManager: ResourceManager, engineReleaseProvider: ReleaseProvider[EngineRelease], runtimeReleaseProvider: GraalVMRuntimeReleaseProvider, - componentConfig: RuntimeComponentConfiguration, - componentUpdaterFactory: RuntimeComponentUpdaterFactory, implicit private val installerKind: InstallerKind ) { private val logger = Logger[RuntimeVersionManager] - private val os = OS.operatingSystem /** Tries to find a GraalVM runtime for the provided engine. * * Returns None if the runtime is missing. */ - def findGraalRuntime(engine: Engine): Option[GraalRuntime] = - findGraalRuntime(engine.manifest.runtimeVersion) + def findGraalRuntime(engine: Engine): Option[GraalRuntime] = { + Option(graalVersionManager.findGraalRuntime(engine)) + } /** Finds an installed GraalVM runtime with the given `version`. * * Returns None if that version is not installed. */ def findGraalRuntime(version: GraalVMVersion): Option[GraalRuntime] = { - val explicitPathOpt = this.environment.getEnvPath("ENSO_JVM_PATH") - val graalRuntimeOpt = explicitPathOpt - .map(path => { - val runtime = GraalRuntime(version, path) - runtime.ensureValid() - runtime - }) - .orElse { - val pathOpt = findGraalRuntimeOnSearchPath(version) - pathOpt.map { path => - // TODO [RW] for now an exception is thrown if the installation is - // corrupted, in #1052 offer to repair the broken installation - loadGraalRuntime(path).recoverWith { case e: Exception => - Failure( - UnrecognizedComponentError( - s"The runtime $version is already installed, but cannot be " + - s"loaded due to $e. Until the launcher gets an auto-repair " + - s"feature, please try reinstalling the runtime by " + - s"uninstalling all engines that use it and installing them " + - s"again, or manually removing `$path`", - e - ) - ) - }.get - } - } - graalRuntimeOpt match { - case Some(graalRuntime) => - logger.debug("Found GraalVM runtime [{}]", graalRuntime) - case None => - logger.debug("GraalVM runtime [{}] not found", version) - } - graalRuntimeOpt - } - - private def findGraalRuntimeOnSearchPath( - version: GraalVMVersion - ): Option[Path] = { - val name = graalRuntimeNameForVersion(version) - firstExisting(distributionManager.paths.runtimeSearchPaths.map(_ / name)) + Option(graalVersionManager.findGraalRuntime(version)); } /** Executes the provided action with a requested engine version. @@ -635,70 +590,13 @@ class RuntimeVersionManager( private def engineNameForVersion(version: SemVer): String = version.toString - /** Returns name of the directory containing the runtime of that version. - */ - private def graalRuntimeNameForVersion(version: GraalVMVersion): String = { - s"graalvm-ce-java${version.javaVersion}-${version.graalVersion}" - } - /** Loads the GraalVM runtime definition. */ private def loadGraalRuntime(path: Path): Try[GraalRuntime] = { - logger.debug("Loading Graal runtime [{}]", path) - val name = path.getFileName.toString - for { - version <- parseGraalRuntimeVersionString(name) - .toRight( - UnrecognizedComponentError(s"Invalid runtime component name `$name`.") - ) - .toTry - runtime = GraalRuntime(version, path) - _ <- runtime.ensureValid() - _ <- installRequiredRuntimeComponents(runtime).recover { - case NonFatal(error) => - val msg = translateError(error) - logger.warn( - "Failed to install required components on the existing [{}]. " + - "Some language features may be unavailable. {}", - runtime, - msg - ) - } - } yield runtime - } - - /** Provide human-readable error messages for OS-specific failures - * @param cause exception thrown when executing the process - * @return human-readable error message - */ - private def translateError(cause: Throwable): String = { - val msg = cause.getMessage - OS.operatingSystem match { - case OS.Linux => msg - case OS.MacOS => msg - case OS.Windows => - if (msg.contains("-1073741515")) { - "Required Microsoft Visual C++ installation is missing" - } else { - msg - } - } - } - - /** Gets the runtime version from its name. - */ - private def parseGraalRuntimeVersionString( - name: String - ): Option[GraalVMVersion] = { - val regex = """graalvm-ce-java(.+)-(.+)""".r - name match { - case regex(javaVersionString, graalVersionString) => - Some(GraalVMVersion(graalVersionString, javaVersionString)) - case _ => - logger.warn( - s"Unrecognized runtime name `$name`" - ) - None + try { + Success(graalVersionManager.loadGraalRuntime(path)) + } catch { + case e: UnrecognizedComponentError => Failure(e) } } @@ -800,26 +698,16 @@ class RuntimeVersionManager( try { logger.debug("Loading temporary runtime [{}]", runtimeTemporaryPath) - val temporaryRuntime = - loadGraalRuntime(runtimeTemporaryPath).recoverWith { error => - Failure( - InstallationError( - "Cannot load the installed runtime. The package may have " + - "been corrupted. Reverting installation", - error - ) + + loadGraalRuntime(runtimeTemporaryPath).recoverWith { error => + Failure( + InstallationError( + "Cannot load the installed runtime. The package may have " + + "been corrupted. Reverting installation", + error ) - }.get - logger.debug("Installing GraalVM components to [{}]", temporaryRuntime) - installRequiredRuntimeComponents(temporaryRuntime).recoverWith { - error => - Failure( - InstallationError( - "fatal: Cannot install the required runtime components", - error - ) - ) - }.get + ) + } val runtimePath = distributionManager.paths.runtimes / runtimeDirectoryName @@ -849,32 +737,6 @@ class RuntimeVersionManager( } } - /** Install components required for the specified runtime on the specified OS. - * - * @param runtime the GraalVM runtime - */ - private def installRequiredRuntimeComponents( - runtime: GraalRuntime - ): Try[Unit] = { - logger.debug("Installing GraalVM components [{}, {}]", runtime, os) - val cu = componentUpdaterFactory.build(runtime) - val requiredComponents = - componentConfig.getRequiredComponents(runtime.version, os) - - if (requiredComponents.isEmpty) Success(()) - else { - for { - installedComponents <- cu.list() - _ = logger.debug( - "Available GraalVM components: [{}]", - installedComponents - ) - missingComponents = requiredComponents.diff(installedComponents) - _ <- cu.install(missingComponents) - } yield () - } - } - private def engineDirectoryNameForVersion(version: SemVer): Path = Path.of(version.toString()) @@ -931,33 +793,6 @@ class RuntimeVersionManager( FileSystem.removeDirectory(temporaryPath) } - /** Logs on trace level all installed engines and runtimes. - * - * NOTE: Useful for debugging but should not be added to production code since it may - * cause unnecessary installations for different engine versions. - */ - def logAvailableComponentsForDebugging(): Unit = logger.whenTraceEnabled { - logger.trace("Discovering available components...") - val engines = for (engine <- listInstalledEngines()) yield { - val runtime = findGraalRuntime(engine) - val runtimeName = runtime - .map(_.toString) - .getOrElse("no runtime found") - val broken = if (engine.isMarkedBroken) " (broken)" else "" - s" - Enso ${engine.version}$broken [runtime: $runtimeName] " + - s"[location: ${MaskedPath(engine.path).applyMasking()}]" - } - - val runtimes = - for (runtime <- listInstalledGraalRuntimes()) - yield s" - $runtime [location: " + - s"${MaskedPath(runtime.path).applyMasking()}]" - - logger.trace( - s"Installed engines (${engines.length}):\n${engines.mkString("\n")}\n\n" + - s"Installed runtimes (${runtimes.length}):\n${runtimes.mkString("\n")}" - ) - } } /* Note [RuntimeVersionManager Concurrency Model] diff --git a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/UnchainedGraalVMComponentUpdater.scala b/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/UnchainedGraalVMComponentUpdater.scala deleted file mode 100644 index 271ebf7584..0000000000 --- a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/UnchainedGraalVMComponentUpdater.scala +++ /dev/null @@ -1,26 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import scala.util.{Success, Try} - -/** A dummy component updater for [[GraalVMVersion.isUnchained unchained]] GraalVM. - * There is no `gu` utility in unchained GraalVM, so this updater does not do anything. - * It only lists the components that are known to be included in the unchained GraalVM. - */ -class UnchainedGraalVMComponentUpdater extends RuntimeComponentUpdater { - - /** There - * - * @return the list of installed runtime components - */ - override def list(): Try[Seq[GraalVMComponent]] = Success(Seq()) - - /** Install the provided runtime components. - * - * @param components the list of components to install - */ - override def install(components: Seq[GraalVMComponent]): Try[Unit] = { - throw new IllegalStateException( - "Cannot install components in unchained GraalVM" - ) - } -} diff --git a/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfigurationSpec.scala b/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfigurationSpec.scala deleted file mode 100644 index b5a00650fe..0000000000 --- a/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentConfigurationSpec.scala +++ /dev/null @@ -1,106 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import org.enso.cli.OS -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec - -class GraalVMComponentConfigurationSpec extends AnyWordSpec with Matchers { - - "RuntimeComponentConfiguration" should { - - "return required components" in { - val conf = new GraalVMComponentConfiguration - val required = Seq(GraalVMComponent.python, GraalVMComponent.R) - val requiredAbove22 = required ++ Seq(GraalVMComponent.js) - - conf.getRequiredComponents( - GraalVMVersion("21.0.0.2", "11"), - OS.Linux - ) should contain theSameElementsAs required - - conf.getRequiredComponents( - GraalVMVersion("21.0.0.2", "11"), - OS.MacOS - ) should contain theSameElementsAs required - - conf.getRequiredComponents( - GraalVMVersion("21.0.0.2", "11"), - OS.Windows - ) should contain theSameElementsAs Seq() - - conf.getRequiredComponents( - GraalVMVersion("22.0.0.0", "11"), - OS.Linux - ) should contain theSameElementsAs requiredAbove22 - - conf.getRequiredComponents( - GraalVMVersion("22.3.1", "17"), - OS.MacOS - ) should contain theSameElementsAs requiredAbove22 - - conf.getRequiredComponents( - GraalVMVersion("22.3.1", "17"), - OS.Windows - ) should contain theSameElementsAs Seq( - GraalVMComponent.js - ) - - conf.getRequiredComponents( - GraalVMVersion("22.3.1", "17"), - OS.Linux - ) should contain theSameElementsAs Seq( - GraalVMComponent.js, - GraalVMComponent.python, - GraalVMComponent.R - ) - - conf.getRequiredComponents( - GraalVMVersion("20.0.0.0", "11"), - OS.Linux - ) should contain theSameElementsAs Seq() - - conf.getRequiredComponents( - GraalVMVersion("23.0.0", "17.0.7+7.1"), - OS.Linux - ) should contain theSameElementsAs Seq( - GraalVMComponent.js, - GraalVMComponent.python - ) - - conf.getRequiredComponents( - GraalVMVersion("23.0.0", "11"), - OS.Linux - ) should contain theSameElementsAs Seq( - GraalVMComponent.js, - GraalVMComponent.python - ) - - conf.getRequiredComponents( - GraalVMVersion("23.0.0", "17.0.7+7.1"), - OS.Windows - ) should contain theSameElementsAs Seq( - GraalVMComponent.js - ) - } - - "return no required components for Truffle unchained" in { - val conf = new GraalVMComponentConfiguration - val versions = Seq( - GraalVMVersion("23.0.0", "21"), - GraalVMVersion("23.0.1", "21"), - GraalVMVersion("23.0.0", "21.0.1"), - GraalVMVersion("23.0.1", "21.0.1"), - GraalVMVersion("23.0.0", "21.0.1+5.1"), - GraalVMVersion("23.0.1", "21.0.1+5.1"), - GraalVMVersion("23.1.0", "21") - ) - versions.forall(_.isUnchained) shouldBe true - versions.foreach(version => { - conf.getRequiredComponents( - version, - OS.Linux - ) shouldBe empty - }) - } - } -} diff --git a/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentParserSpec.scala b/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentParserSpec.scala deleted file mode 100644 index 52cb439017..0000000000 --- a/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMComponentParserSpec.scala +++ /dev/null @@ -1,57 +0,0 @@ -package org.enso.runtimeversionmanager.components - -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec - -class GraalVMComponentParserSpec extends AnyWordSpec with Matchers { - - "RuntimeComponentUpdater" should { - - "parse list output" in { - val listOut = - """ - |ID : js - |Name : Graal.js - |Version : 21.0.0.2 - |GraalVM : n/a - |Stability: - - |Origin : - | - |ID : graalvm - |Name : GraalVM Core - |Version : 21.0.0.2 - |GraalVM : n/a - |Stability: - - |Origin : - | - |ID : R - |Name : FastR - |Version : 21.0.0.2 - |GraalVM : 21.0.0.2 - |Stability: Experimental - |Origin : https://github.com/oracle/fastr/releases/download/vm-21.0.0.2/r-installable-java11-linux-amd64-21.0.0.2.jar - | - |ID : llvm-toolchain - |Name : LLVM.org toolchain - |Version : 21.0.0.2 - |GraalVM : 21.0.0.2 - |Stability: Supported - |Origin : https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/llvm-toolchain-installable-java11-linux-amd64-21.0.0.2.jar - | - |ID : native-image - |Name : Native Image - |Version : 21.0.0.2 - |GraalVM : 21.0.0.2 - |Stability: Early adopter - |Origin : https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/native-image-installable-svm-java11-linux-amd64-21.0.0.2.jar - |""".stripMargin - - val expectedComponents = - Seq("js", "graalvm", "R", "llvm-toolchain", "native-image") - .map(GraalVMComponent(_)) - val components = - GraalVMComponentUpdater.ListOut.parse(listOut.linesIterator.toSeq) - components shouldEqual expectedComponents - } - } -} diff --git a/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMVersionSpec.scala b/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMVersionSpec.scala new file mode 100644 index 0000000000..dabcc5188b --- /dev/null +++ b/lib/scala/runtime-version-manager/src/test/scala/org/enso/runtimeversionmanager/components/GraalVMVersionSpec.scala @@ -0,0 +1,40 @@ +package org.enso.runtimeversionmanager.components + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +class GraalVMVersionSpec extends AnyWordSpec with Matchers { + + "GraalVM Version" should { + "greater JDK version is considered newer" in { + val graalVersion = "24.0.0" + val ver1 = GraalVMVersion(graalVersion, "21.0.2") + val ver2 = GraalVMVersion(graalVersion, "17.0.7") + (ver1.compareTo(ver2) > 0) shouldBe true + } + + "If JDK version is same (semver), greater Graal version is newer" in { + val jdkVersion = "21.0.2" + val ver1 = GraalVMVersion("24.0.2", jdkVersion) + val ver2 = GraalVMVersion("24.0.0", jdkVersion) + (ver1.compareTo(ver2) > 0) shouldBe true + } + + "If JDK version is same (non semver), greater Graal version is newer" in { + val jdkVersion = "21" + val ver1 = GraalVMVersion("24.0.2", jdkVersion) + val ver2 = GraalVMVersion("24.0.0", jdkVersion) + (ver1.compareTo(ver2) > 0) shouldBe true + } + + "be correctly ordered" in { + val ver1 = GraalVMVersion("24.0.0", "21.0.2") + val ver2 = GraalVMVersion("23.1.2", "21.0.2") + val ver3 = GraalVMVersion("23.1.0", "21.0.1") + val ver4 = GraalVMVersion("23.0.0", "17.0.7") + val lst = List(ver4, ver2, ver3, ver1) + val sortedList = lst.sortWith((ver1, ver2) => ver1.compareTo(ver2) < 0) + sortedList shouldEqual List(ver4, ver3, ver2, ver1) + } + } +} diff --git a/lib/scala/semver/src/test/java/org/enso/semver/VersionsTest.java b/lib/scala/semver/src/test/java/org/enso/semver/VersionsTest.java index 188ba465e3..0a865378db 100644 --- a/lib/scala/semver/src/test/java/org/enso/semver/VersionsTest.java +++ b/lib/scala/semver/src/test/java/org/enso/semver/VersionsTest.java @@ -12,6 +12,8 @@ public class VersionsTest { assertTrue(SemVer.parse("0.1.1").isSuccess()); assertTrue(SemVer.parse("9999.0.0").isSuccess()); assertTrue(SemVer.parse("0.1").isFailure()); + assertTrue(SemVer.parse("21.0.2").isSuccess()); + assertTrue(SemVer.parse("17.0.7").isSuccess()); } @Test diff --git a/lib/scala/version-output/src/main/java/org/enso/version/BuildVersion.java b/lib/scala/version-output/src/main/java/org/enso/version/BuildVersion.java index a5d3b54f3a..e9261bbcaa 100644 --- a/lib/scala/version-output/src/main/java/org/enso/version/BuildVersion.java +++ b/lib/scala/version-output/src/main/java/org/enso/version/BuildVersion.java @@ -19,10 +19,23 @@ public class BuildVersion { return GeneratedVersion.scalacVersion(); } + /** + * Version of GraalVM, more specifically, version of the GraalVM and Truffle libraries used to + * build the engine. + */ public static String graalVersion() { return GeneratedVersion.graalVersion(); } + /** + * Version of Java (JDK) used to build the engine. + * + * @return + */ + public static String javaVersion() { + return GeneratedVersion.javaVersion(); + } + public static String currentEdition() { return GeneratedVersion.currentEdition(); } diff --git a/project/BuildInfo.scala b/project/BuildInfo.scala index 44c7fad93f..4e84c96f1f 100644 --- a/project/BuildInfo.scala +++ b/project/BuildInfo.scala @@ -18,6 +18,7 @@ object BuildInfo { * @param ensoVersion Enso version * @param scalacVersion Scala compiler version used in the project * @param graalVersion GraalVM version used in the project + * @param javaVersion Java language version used in the project. * @param currentEdition name of the edition associated with the Enso * version; this should be removed once #1831 is * implemented @@ -30,6 +31,7 @@ object BuildInfo { ensoVersion: String, scalacVersion: String, graalVersion: String, + javaVersion: String, currentEdition: String ): Seq[File] = { val gitInfo = getGitInformation(log).getOrElse(fallbackGitInformation) @@ -58,6 +60,10 @@ object BuildInfo { | return "${graalVersion}"; | } | + | static String javaVersion() { + | return "${javaVersion}"; + | } + | | static String currentEdition() { | return "${currentEdition}"; | } diff --git a/tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-ignore b/tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-ignore deleted file mode 100644 index ac3adb92c9..0000000000 --- a/tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-ignore +++ /dev/null @@ -1,8 +0,0 @@ -Copyright (C) 2015-2022 Lightbend Inc. -Copyright (C) 2016-2022 Lightbend Inc. -Copyright (C) 2017-2022 Lightbend Inc. -Copyright (C) 2018-2022 Lightbend Inc. -Copyright (C) 2019-2022 Lightbend Inc. -Copyright (C) 2020-2022 Lightbend Inc. -Copyright (C) 2021-2022 Lightbend Inc. -Copyright 2009-2020 Lightbend Inc. diff --git a/tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-keep b/tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-keep deleted file mode 100644 index 86256d6119..0000000000 --- a/tools/legal-review/launcher/com.typesafe.akka.akka-http-core_2.13-10.2.10/copyright-keep +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2008-2017 Bjoern Hoehrmann -Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev -Copyright (C) 2009-2022 Lightbend Inc. -Copyright 2011 Mark Harrah, Eugene Yokota -Copyright 2014 Twitter, Inc. -Copyright 2015 Heiko Seeberger diff --git a/tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-ignore b/tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-ignore deleted file mode 100644 index aa3e5cce83..0000000000 --- a/tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-ignore +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2009-2020 Lightbend Inc. -Copyright (C) 2009-2022 Lightbend Inc. -Copyright (C) 2015-2022 Lightbend Inc. -Copyright (C) 2017-2022 Lightbend Inc. -Copyright (C) 2018-2022 Lightbend Inc. -Copyright (C) 2020-2022 Lightbend Inc. diff --git a/tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-keep b/tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-keep deleted file mode 100644 index e25cd2d998..0000000000 --- a/tools/legal-review/launcher/com.typesafe.akka.akka-http_2.13-10.2.10/copyright-keep +++ /dev/null @@ -1 +0,0 @@ -Copyright (C) 2009-2020 Lightbend Inc. diff --git a/tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-ignore b/tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-ignore deleted file mode 100644 index 6da40a864f..0000000000 --- a/tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-ignore +++ /dev/null @@ -1,2 +0,0 @@ -Copyright (C) 2019-2022 Lightbend Inc. -Copyright (c) 2013-14 Miles Sabin diff --git a/tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-keep b/tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-keep deleted file mode 100644 index 141594ba9e..0000000000 --- a/tools/legal-review/launcher/com.typesafe.akka.akka-parsing_2.13-10.2.10/copyright-keep +++ /dev/null @@ -1,4 +0,0 @@ -Copyright (C) 2009-2017 Mathias Doenitz, Alexander Myltsev -Copyright (C) 2009-2022 Lightbend Inc. -Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com) -Copyright (c) 2011-13 Miles Sabin diff --git a/tools/legal-review/launcher/report-state b/tools/legal-review/launcher/report-state index 2617247d9c..a02587526a 100644 --- a/tools/legal-review/launcher/report-state +++ b/tools/legal-review/launcher/report-state @@ -1,3 +1,3 @@ -5BE1C47CDA76AF7E6C42089993BEA2B8DB544C1752AE5D8055BF2B4E713B20EA -E92B79099FF706DC1F50287D428322268954285BD62F19B0A70456E3356AE1D1 +BBB2B5E440C388A022983CB2C0B9B4BA68D04B97FC07E4C8E142952448437BE0 +CA8B1BB2992E828BA958FD6CFC0076B213170FCD454406131407ED0340EC7F2F 0 From c52b8f945576700c4544581bfa3e716253d45c4c Mon Sep 17 00:00:00 2001 From: Ilya Bogdanov Date: Tue, 19 Nov 2024 15:36:59 +0400 Subject: [PATCH 03/15] Disable EditContext API (#11554) Fixes #11239 https://github.com/user-attachments/assets/eb57fb34-11f4-489b-9849-c93c7aa5e870 --- app/gui/src/project-view/components/CodeEditor.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/gui/src/project-view/components/CodeEditor.vue b/app/gui/src/project-view/components/CodeEditor.vue index 65c2286e98..6cd00bb2ca 100644 --- a/app/gui/src/project-view/components/CodeEditor.vue +++ b/app/gui/src/project-view/components/CodeEditor.vue @@ -93,6 +93,8 @@ const expressionUpdatesDiagnostics = computed(() => { // == CodeMirror editor setup == +// Disable EditContext API because of https://github.com/codemirror/dev/issues/1458. +;(EditorView as any).EDIT_CONTEXT = false const editorView = new EditorView() const viewInitialized = ref(false) watchEffect(() => { From af39e0ec50c1b59aa0c8ee85c6bb510279a505aa Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 19 Nov 2024 16:47:46 +0100 Subject: [PATCH 04/15] Pasting image in Documentation Editor (#11547) Fixes #10059 https://github.com/user-attachments/assets/a528e26a-b388-4a2a-9bf4-3ccc734373f6 # Important Notes * I put the logic for project's files management to a single composable "projectFiles" --- CHANGELOG.md | 3 + app/gui/e2e/project-view/rightPanel.spec.ts | 11 +- app/gui/src/project-view/bindings.ts | 1 + .../components/DocumentationEditor.vue | 154 +++++++++++- .../project-view/components/GraphEditor.vue | 10 +- .../components/GraphEditor/upload.ts | 127 +++------- .../components/MarkdownEditor.vue | 17 +- .../MarkdownEditor/DocumentationImage.vue | 7 +- .../MarkdownEditor/MarkdownEditorImpl.vue | 32 ++- .../MarkdownEditor/__tests__/markdown.test.ts | 15 ++ .../MarkdownEditor/imageUrlTransformer.ts | 28 ++- .../MarkdownEditor/markdown/decoration.ts | 18 +- .../MarkdownEditor/markdown/lezer.d.ts | 11 + .../MarkdownEditor/markdown/parse.ts | 223 +++++++++++++++++- app/gui/src/project-view/mock/engine.ts | 16 ++ .../src/project-view/stores/project/index.ts | 29 +-- .../src/project-view/stores/projectFiles.ts | 150 ++++++++++++ .../src/project-view/util/net/dataServer.ts | 7 +- app/gui/src/project-view/util/toast.ts | 25 +- tsconfig.json | 4 +- 20 files changed, 726 insertions(+), 162 deletions(-) create mode 100644 app/gui/src/project-view/stores/projectFiles.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b27e76ed78..f31e9a856f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ component.][11452] - [New documentation editor provides improved Markdown editing experience, and paves the way for new documentation features.][11469] +- [You can now add images to documentation panel][11547] by pasting them from + clipboard or by drag'n'dropping image files. - ["Write" button in component menu allows to evaluate it separately from the rest of the workflow][11523]. @@ -42,6 +44,7 @@ [11448]: https://github.com/enso-org/enso/pull/11448 [11452]: https://github.com/enso-org/enso/pull/11452 [11469]: https://github.com/enso-org/enso/pull/11469 +[11547]: https://github.com/enso-org/enso/pull/11547 [11523]: https://github.com/enso-org/enso/pull/11523 #### Enso Standard Library diff --git a/app/gui/e2e/project-view/rightPanel.spec.ts b/app/gui/e2e/project-view/rightPanel.spec.ts index bc907fbe2d..3f2eb5ef73 100644 --- a/app/gui/e2e/project-view/rightPanel.spec.ts +++ b/app/gui/e2e/project-view/rightPanel.spec.ts @@ -7,13 +7,18 @@ import * as locate from './locate' test('Main method documentation', async ({ page }) => { await actions.goToGraph(page) + const rightDock = locate.rightDock(page) // Documentation panel hotkey opens right-dock. - await expect(locate.rightDock(page)).toBeHidden() + await expect(rightDock).toBeHidden() await page.keyboard.press(`${CONTROL_KEY}+D`) - await expect(locate.rightDock(page)).toBeVisible() + await expect(rightDock).toBeVisible() // Right-dock displays main method documentation. - await expect(locate.editorRoot(locate.rightDock(page))).toHaveText('The main method') + await expect(locate.editorRoot(rightDock)).toContainText('The main method') + // All three images are loaded properly + await expect(rightDock.getByAltText('Image')).toHaveCount(3) + for (const img of await rightDock.getByAltText('Image').all()) + await expect(img).toHaveJSProperty('naturalWidth', 3) // Documentation hotkey closes right-dock.p await page.keyboard.press(`${CONTROL_KEY}+D`) diff --git a/app/gui/src/project-view/bindings.ts b/app/gui/src/project-view/bindings.ts index 210094aeb6..defe7cb055 100644 --- a/app/gui/src/project-view/bindings.ts +++ b/app/gui/src/project-view/bindings.ts @@ -12,6 +12,7 @@ export const codeEditorBindings = defineKeybinds('code-editor', { export const documentationEditorBindings = defineKeybinds('documentation-editor', { toggle: ['Mod+D'], openLink: ['Mod+PointerMain'], + paste: ['Mod+V'], }) export const interactionBindings = defineKeybinds('current-interaction', { diff --git a/app/gui/src/project-view/components/DocumentationEditor.vue b/app/gui/src/project-view/components/DocumentationEditor.vue index fc19d6b708..240aae6e4b 100644 --- a/app/gui/src/project-view/components/DocumentationEditor.vue +++ b/app/gui/src/project-view/components/DocumentationEditor.vue @@ -1,13 +1,17 @@