mirror of
https://github.com/enso-org/enso.git
synced 2024-12-27 04:52:13 +03:00
Notification about the project rename action (#7613)
close #7604 After moving the rename action to the dashboard, IDE is unaware of the new project name. PR implements a new `refactoring/projectRenamed` notification that is sent from the server to clients and informs them about the changed project name. # Important Notes https://github.com/enso-org/enso/assets/357683/7c62726d-217e-4e69-8e48-568e0b7b8c34
This commit is contained in:
parent
54bd83da1e
commit
5dc2c4c5fd
@ -919,6 +919,7 @@
|
||||
- [Support renaming variable or function][7515]
|
||||
- [Only use types as State keys][7585]
|
||||
- [Allow Java Enums in case of branches][7607]
|
||||
- [Notification about the project rename action][7613]
|
||||
|
||||
[3227]: https://github.com/enso-org/enso/pull/3227
|
||||
[3248]: https://github.com/enso-org/enso/pull/3248
|
||||
@ -1052,6 +1053,7 @@
|
||||
[7515]: https://github.com/enso-org/enso/pull/7515
|
||||
[7585]: https://github.com/enso-org/enso/pull/7585
|
||||
[7607]: https://github.com/enso-org/enso/pull/7607
|
||||
[7613]: https://github.com/enso-org/enso/pull/7613
|
||||
|
||||
# Enso 2.0.0-alpha.18 (2021-10-12)
|
||||
|
||||
|
@ -174,6 +174,10 @@ pub enum Notification {
|
||||
/// visualization.
|
||||
#[serde(rename = "executionContext/visualizationEvaluationFailed")]
|
||||
VisualizationEvaluationFailed(VisualizationEvaluationFailed),
|
||||
|
||||
/// Sent from server to the client to inform that the project has been renamed.
|
||||
#[serde(rename = "refactoring/projectRenamed")]
|
||||
ProjectRenamed(ProjectRenamed),
|
||||
}
|
||||
|
||||
/// Sent from the server to the client to inform about a failure during execution of an execution
|
||||
@ -382,6 +386,25 @@ pub struct TextFileModifiedOnDisk {
|
||||
|
||||
|
||||
|
||||
// =================================
|
||||
// === Refactoring Notifications ===
|
||||
// =================================
|
||||
|
||||
/// The `refactoring/projectRenamed` notification parameters.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProjectRenamed {
|
||||
/// The old normalized project name.
|
||||
pub old_normalized_name: String,
|
||||
/// The new normalized project name.
|
||||
pub new_normalized_name: String,
|
||||
/// The new display project name.
|
||||
pub new_name: String,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ======================
|
||||
// === FileAttributes ===
|
||||
// ======================
|
||||
|
@ -88,10 +88,6 @@ pub trait API: Debug {
|
||||
context_id: model::execution_context::Id,
|
||||
) -> BoxFuture<'a, FallibleResult<model::ExecutionContext>>;
|
||||
|
||||
/// Set a new project name.
|
||||
#[allow(clippy::needless_lifetimes)] // Note: Needless lifetimes
|
||||
fn rename_project<'a>(&'a self, name: String) -> BoxFuture<'a, FallibleResult<()>>;
|
||||
|
||||
/// Returns the primary content root id for this project.
|
||||
fn project_content_root_id(&self) -> Uuid {
|
||||
self.json_rpc().project_root().id()
|
||||
@ -184,6 +180,8 @@ pub enum Notification {
|
||||
ExecutionComplete,
|
||||
/// Indicates failure of the project execution.
|
||||
ExecutionFailed,
|
||||
/// Project has been renamed.
|
||||
Renamed,
|
||||
}
|
||||
|
||||
/// Denotes one of backend connections used by a project.
|
||||
|
@ -225,6 +225,22 @@ async fn reload_module_on_file_change(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update internal state when the `refactoring/projectRenamed` notification received.
|
||||
#[profile(Detail)]
|
||||
fn rename_project_on_notification(
|
||||
project_renamed: language_server::types::ProjectRenamed,
|
||||
properties: Rc<RefCell<Properties>>,
|
||||
execution_contexts: Rc<ExecutionContextsRegistry>,
|
||||
) {
|
||||
{
|
||||
let mut properties = properties.borrow_mut();
|
||||
properties.displayed_name = project_renamed.new_name.into();
|
||||
properties.project_name.project = project_renamed.new_normalized_name.clone().into();
|
||||
}
|
||||
execution_contexts
|
||||
.rename_project(project_renamed.old_normalized_name, project_renamed.new_normalized_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
@ -522,10 +538,13 @@ impl Project {
|
||||
let publisher = self.notifications.clone_ref();
|
||||
let project_root_id = self.project_content_root_id();
|
||||
let language_server = self.json_rpc().clone_ref();
|
||||
let properties = self.properties.clone_ref();
|
||||
let execution_contexts = self.execution_contexts.clone_ref();
|
||||
let weak_suggestion_db = Rc::downgrade(&self.suggestion_db);
|
||||
let weak_content_roots = Rc::downgrade(&self.content_roots);
|
||||
let weak_module_registry = Rc::downgrade(&self.module_registry);
|
||||
let execution_update_handler = self.execution_update_handler();
|
||||
|
||||
move |event| {
|
||||
debug!("Received an event from the json-rpc protocol: {event:?}");
|
||||
use engine_protocol::language_server::Event;
|
||||
@ -618,6 +637,13 @@ impl Project {
|
||||
update.message
|
||||
);
|
||||
}
|
||||
Event::Notification(Notification::ProjectRenamed(project_renamed)) => {
|
||||
let properties = properties.clone_ref();
|
||||
let execution_contexts = execution_contexts.clone_ref();
|
||||
rename_project_on_notification(project_renamed, properties, execution_contexts);
|
||||
let notification = model::project::Notification::Renamed;
|
||||
publisher.notify(notification);
|
||||
}
|
||||
Event::Closed => {
|
||||
error!("Lost JSON-RPC connection with the Language Server!");
|
||||
let which = model::project::BackendConnection::LanguageServerJson;
|
||||
@ -750,33 +776,6 @@ impl model::project::API for Project {
|
||||
.boxed_local()
|
||||
}
|
||||
|
||||
fn rename_project(&self, name: String) -> BoxFuture<FallibleResult> {
|
||||
if self.read_only() {
|
||||
std::future::ready(Err(RenameInReadOnly.into())).boxed_local()
|
||||
} else {
|
||||
async move {
|
||||
let old_name = self.properties.borrow_mut().project_name.project.clone_ref();
|
||||
let referent_name = name.to_im_string();
|
||||
let project_manager =
|
||||
self.project_manager.as_ref().ok_or(ProjectManagerUnavailable)?;
|
||||
let project_id = self.properties.borrow().id;
|
||||
let project_name = ProjectName::new_unchecked(name);
|
||||
project_manager.rename_project(&project_id, &project_name).await.map_err(
|
||||
|error| match error {
|
||||
RpcError::RemoteError(cause)
|
||||
if cause.code == code::PROJECT_NAME_INVALID =>
|
||||
failure::Error::from(ProjectNameInvalid { cause: cause.message }),
|
||||
error => error.into(),
|
||||
},
|
||||
)?;
|
||||
self.properties.borrow_mut().project_name.project = referent_name.clone_ref();
|
||||
self.execution_contexts.rename_project(old_name, referent_name);
|
||||
Ok(())
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
fn project_content_root_id(&self) -> Uuid {
|
||||
self.language_server_rpc.project_root().id()
|
||||
}
|
||||
|
@ -224,6 +224,11 @@ impl Model {
|
||||
self.view.top_bar().project_name().set_project_changed(changed);
|
||||
}
|
||||
|
||||
fn project_renamed(&self) {
|
||||
let actual_name = self.controller.model.name();
|
||||
self.view.top_bar().project_name().set_name(actual_name);
|
||||
}
|
||||
|
||||
fn execution_complete(&self) {
|
||||
self.view.graph().frp.set_read_only(false);
|
||||
self.view.graph().frp.execution_complete.emit(());
|
||||
@ -502,6 +507,9 @@ impl Project {
|
||||
Notification::ExecutionFailed => {
|
||||
model.execution_failed();
|
||||
}
|
||||
Notification::Renamed => {
|
||||
model.project_renamed();
|
||||
}
|
||||
};
|
||||
std::future::ready(())
|
||||
});
|
||||
|
@ -50,8 +50,6 @@
|
||||
//! [`SpanWidget::PRIORITY_OVER_OVERRIDE`] as `true` in their implementation. In that case, the
|
||||
//! override will be applied again on their children that use the same span-tree node.
|
||||
|
||||
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::component::node::input::area::NODE_HEIGHT;
|
||||
|
@ -126,6 +126,7 @@ transport formats, please look [here](./protocol-architecture).
|
||||
- [Refactoring](#refactoring)
|
||||
- [`refactoring/renameProject`](#refactoringrenameproject)
|
||||
- [`refactoring/renameSymbol`](#refactoringrenamesymbol)
|
||||
- [`refactoring/projectRenamed`](#refactoringprojectrenamed)
|
||||
- [Execution Management Operations](#execution-management-operations)
|
||||
- [Execution Management Example](#execution-management-example)
|
||||
- [Create Execution Context](#create-execution-context)
|
||||
@ -3412,6 +3413,41 @@ Current limitations of the method renaming are:
|
||||
- [`RefactoringNotSupported`](#refactoringnotsupported) to signal that the
|
||||
refactoring of the given expression is not supported.
|
||||
|
||||
### `refactoring/projectRenamed`
|
||||
|
||||
This is a notification sent from the server to the clients to inform them about
|
||||
the new project name.
|
||||
|
||||
- **Type:** Notification
|
||||
- **Direction:** Server -> Client
|
||||
- **Connection:** Protocol
|
||||
- **Visibility:** Public
|
||||
|
||||
#### Parameters
|
||||
|
||||
```typescript
|
||||
{
|
||||
/**
|
||||
* Old normalized name of the project.
|
||||
*/
|
||||
oldNormalizedName: string;
|
||||
|
||||
/**
|
||||
* New normalized name of the prject.
|
||||
*/
|
||||
newNormalizedName: string;
|
||||
|
||||
/**
|
||||
* New display name of the project.
|
||||
*/
|
||||
newName: string;
|
||||
}
|
||||
```
|
||||
|
||||
#### Errors
|
||||
|
||||
None
|
||||
|
||||
## Execution Management Operations
|
||||
|
||||
The execution management portion of the language server API deals with exposing
|
||||
|
@ -36,6 +36,7 @@ import org.enso.languageserver.refactoring.RefactoringApi.{
|
||||
RenameProject,
|
||||
RenameSymbol
|
||||
}
|
||||
import org.enso.languageserver.refactoring.{RefactoringApi, RefactoringProtocol}
|
||||
import org.enso.languageserver.requesthandler._
|
||||
import org.enso.languageserver.requesthandler.capability._
|
||||
import org.enso.languageserver.requesthandler.io._
|
||||
@ -132,6 +133,13 @@ class JsonConnectionController(
|
||||
|
||||
implicit val timeout: Timeout = Timeout(requestTimeout)
|
||||
|
||||
override def preStart(): Unit = {
|
||||
super.preStart()
|
||||
|
||||
context.system.eventStream
|
||||
.subscribe(self, classOf[RefactoringProtocol.ProjectRenamedNotification])
|
||||
}
|
||||
|
||||
override def receive: Receive = {
|
||||
case JsonRpcServer.WebConnect(webActor) =>
|
||||
unstashAll()
|
||||
@ -416,6 +424,20 @@ class JsonConnectionController(
|
||||
)
|
||||
}
|
||||
|
||||
case RefactoringProtocol.ProjectRenamedNotification(
|
||||
oldNormalizedName,
|
||||
newNormalizedName,
|
||||
newName
|
||||
) =>
|
||||
webActor ! Notification(
|
||||
RefactoringApi.ProjectRenamed,
|
||||
RefactoringApi.ProjectRenamed.Params(
|
||||
oldNormalizedName,
|
||||
newNormalizedName,
|
||||
newName
|
||||
)
|
||||
)
|
||||
|
||||
case Api.ProgressNotification(payload) =>
|
||||
val translated: Notification[_, _] =
|
||||
translateProgressNotification(payload)
|
||||
@ -582,6 +604,10 @@ class JsonConnectionController(
|
||||
libraryConfig.localLibraryManager,
|
||||
libraryConfig.publishedLibraryCache
|
||||
),
|
||||
RenameProject -> RenameProjectHandler.props(
|
||||
requestTimeout,
|
||||
runtimeConnector
|
||||
),
|
||||
RenameSymbol -> RenameSymbolHandler.props(
|
||||
requestTimeout,
|
||||
runtimeConnector
|
||||
|
@ -122,5 +122,6 @@ object JsonRpc {
|
||||
.registerNotification(WaitingForStandardInput)
|
||||
.registerNotification(SuggestionsDatabaseUpdates)
|
||||
.registerNotification(VisualizationEvaluationFailed)
|
||||
.registerNotification(ProjectRenamed)
|
||||
.finalized()
|
||||
}
|
||||
|
@ -27,6 +27,20 @@ object RefactoringApi {
|
||||
}
|
||||
}
|
||||
|
||||
case object ProjectRenamed extends Method("refactoring/projectRenamed") {
|
||||
|
||||
case class Params(
|
||||
oldNormalizedName: String,
|
||||
newNormalizedName: String,
|
||||
newName: String
|
||||
)
|
||||
|
||||
implicit val hasParams: HasParams.Aux[this.type, ProjectRenamed.Params] =
|
||||
new HasParams[this.type] {
|
||||
type Params = ProjectRenamed.Params
|
||||
}
|
||||
}
|
||||
|
||||
case object RenameSymbol extends Method("refactoring/renameSymbol") {
|
||||
|
||||
case class Params(
|
||||
@ -60,4 +74,7 @@ object RefactoringApi {
|
||||
s"Refactoring not supported for expression [$expressionId]"
|
||||
)
|
||||
|
||||
case class ProjectRenameFailed(oldName: String, newName: String)
|
||||
extends Error(9004, s"Project rename failed [$oldName, $newName]")
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package org.enso.languageserver.refactoring
|
||||
|
||||
object RefactoringProtocol {
|
||||
|
||||
/** Notification signaling about the project being renamed.
|
||||
*
|
||||
* @param oldNormalizedName old normalized name of the project
|
||||
* @param newNormalizedName new normalized name of the project
|
||||
* @param newName new display name of the project
|
||||
*/
|
||||
case class ProjectRenamedNotification(
|
||||
oldNormalizedName: String,
|
||||
newNormalizedName: String,
|
||||
newName: String
|
||||
)
|
||||
}
|
@ -1,15 +1,19 @@
|
||||
package org.enso.languageserver.requesthandler.refactoring
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable, Props}
|
||||
import com.typesafe.scalalogging.LazyLogging
|
||||
import org.enso.jsonrpc._
|
||||
import org.enso.languageserver.refactoring.RefactoringApi.RenameProject
|
||||
import org.enso.languageserver.refactoring.RefactoringApi.{
|
||||
ProjectRenameFailed,
|
||||
RenameProject
|
||||
}
|
||||
import org.enso.languageserver.refactoring.RefactoringProtocol
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
/** A request handler for `refactoring/renameProject` commands.
|
||||
@ -52,10 +56,25 @@ class RenameProjectHandler(timeout: FiniteDuration, runtimeConnector: ActorRef)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
case Api.Response(_, Api.ProjectRenamed(_, _)) =>
|
||||
case Api.Response(
|
||||
_,
|
||||
Api.ProjectRenamed(oldNormalizedName, newNormalizedName, newName)
|
||||
) =>
|
||||
context.system.eventStream.publish(
|
||||
RefactoringProtocol.ProjectRenamedNotification(
|
||||
oldNormalizedName,
|
||||
newNormalizedName,
|
||||
newName
|
||||
)
|
||||
)
|
||||
replyTo ! ResponseResult(RenameProject, id, Unused)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case Api.Response(_, Api.ProjectRenameFailed(oldName, newName)) =>
|
||||
replyTo ! ResponseError(Some(id), ProjectRenameFailed(oldName, newName))
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import java.util.UUID
|
||||
* @param executionContextId an execution context of the visualization
|
||||
* @param expression an expression that creates a visualization
|
||||
* @param visualizationModule the name of a module to execute expression at
|
||||
* @param executionContextId an execution context of the visualization
|
||||
* @param expression an expression that creates a visualization
|
||||
*/
|
||||
case class VisualizationConfiguration(
|
||||
executionContextId: UUID,
|
||||
@ -26,7 +24,8 @@ case class VisualizationConfiguration(
|
||||
override def toLogString(shouldMask: Boolean): String =
|
||||
s"VisualizationConfiguration(" +
|
||||
s"executionContextId=$executionContextId," +
|
||||
s"expression=${expression.toLogString(shouldMask)})"
|
||||
s"expression=${expression.toLogString(shouldMask)}," +
|
||||
s"visualizationModule=$visualizationModule)"
|
||||
|
||||
/** Convert to corresponding [[Api]] message. */
|
||||
def toApi: Api.VisualizationConfiguration =
|
||||
|
@ -608,7 +608,7 @@ class LibrariesTest extends BaseServerTest {
|
||||
PackageManager.Default
|
||||
.loadPackage(cachedLibraryRoot.location.toFile)
|
||||
.get
|
||||
pkg.module shouldEqual "Bar"
|
||||
pkg.normalizedName shouldEqual "Bar"
|
||||
pkg
|
||||
.listSources()
|
||||
.map(
|
||||
|
@ -7,6 +7,105 @@ import java.util.UUID
|
||||
|
||||
class RefactoringTest extends BaseServerTest {
|
||||
|
||||
"refactoring/renameProject" should {
|
||||
|
||||
"return ok response after a successful renaming" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
val namespace = "local"
|
||||
val oldName = "Unnamed"
|
||||
val newName = "Project1"
|
||||
|
||||
client.send(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "refactoring/renameProject",
|
||||
"id": 1,
|
||||
"params": {
|
||||
"namespace": $namespace,
|
||||
"oldName": $oldName,
|
||||
"newName": $newName
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
val requestId = runtimeConnectorProbe.receiveN(1).head match {
|
||||
case Api.Request(requestId, payload: Api.RenameProject) =>
|
||||
payload.namespace shouldEqual namespace
|
||||
payload.oldName shouldEqual oldName
|
||||
payload.newName shouldEqual newName
|
||||
requestId
|
||||
case msg =>
|
||||
fail(s"Runtime connector received unexpected message: $msg")
|
||||
}
|
||||
runtimeConnectorProbe.lastSender ! Api.Response(
|
||||
requestId,
|
||||
Api.ProjectRenamed(oldName, newName, newName)
|
||||
)
|
||||
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": null
|
||||
}
|
||||
""")
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "refactoring/projectRenamed",
|
||||
"params": {
|
||||
"oldNormalizedName": $oldName,
|
||||
"newNormalizedName": $newName,
|
||||
"newName": $newName
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
"reply with ProjectRenameFailed in case of failures" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
val namespace = "local"
|
||||
val oldName = "Unnamed"
|
||||
val newName = "Project1"
|
||||
|
||||
client.send(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "refactoring/renameProject",
|
||||
"id": 1,
|
||||
"params": {
|
||||
"namespace": $namespace,
|
||||
"oldName": $oldName,
|
||||
"newName": $newName
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
val requestId = runtimeConnectorProbe.receiveN(1).head match {
|
||||
case Api.Request(requestId, payload: Api.RenameProject) =>
|
||||
payload.namespace shouldEqual namespace
|
||||
payload.oldName shouldEqual oldName
|
||||
payload.newName shouldEqual newName
|
||||
requestId
|
||||
case msg =>
|
||||
fail(s"Runtime connector received unexpected message: $msg")
|
||||
}
|
||||
runtimeConnectorProbe.lastSender ! Api.Response(
|
||||
requestId,
|
||||
Api.ProjectRenameFailed(oldName, newName)
|
||||
)
|
||||
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"error": {
|
||||
"code": 9004,
|
||||
"message": ${s"Project rename failed [$oldName, $newName]"}
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"refactoring/renameSymbol" should {
|
||||
|
||||
"return ok response after a successful renaming" in {
|
||||
|
@ -156,6 +156,10 @@ object Runtime {
|
||||
value = classOf[Api.ProjectRenamed],
|
||||
name = "projectRenamed"
|
||||
),
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[Api.ProjectRenameFailed],
|
||||
name = "projectRenameFailed"
|
||||
),
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[Api.RenameSymbol],
|
||||
name = "renameSymbol"
|
||||
@ -1638,10 +1642,22 @@ object Runtime {
|
||||
|
||||
/** Signals that project has been renamed.
|
||||
*
|
||||
* @param namespace the namespace of the project
|
||||
* @param newName the new project name
|
||||
* @param oldNormalizedName old normalized name of the project
|
||||
* @param newNormalizedName new normalized name of the project
|
||||
* @param newName new display name of the project
|
||||
*/
|
||||
final case class ProjectRenamed(namespace: String, newName: String)
|
||||
final case class ProjectRenamed(
|
||||
oldNormalizedName: String,
|
||||
newNormalizedName: String,
|
||||
newName: String
|
||||
) extends ApiResponse
|
||||
|
||||
/** Signals that project has been renamed.
|
||||
*
|
||||
* @param oldName the old name of the project
|
||||
* @param newName the new name of the project
|
||||
*/
|
||||
final case class ProjectRenameFailed(oldName: String, newName: String)
|
||||
extends ApiResponse
|
||||
|
||||
/** A request for symbol renaming.
|
||||
|
@ -4,7 +4,6 @@ import java.util.logging.Level
|
||||
import org.enso.interpreter.instrument.{CacheInvalidation, InstrumentFrame}
|
||||
import org.enso.interpreter.instrument.execution.RuntimeContext
|
||||
import org.enso.interpreter.instrument.job.{EnsureCompiledJob, ExecuteJob}
|
||||
import org.enso.interpreter.runtime.Module
|
||||
import org.enso.pkg.QualifiedName
|
||||
import org.enso.polyglot.data.Tree
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
@ -40,16 +39,23 @@ class RenameProjectCmd(
|
||||
Level.FINE,
|
||||
s"Renaming project [old:${request.namespace}.${request.oldName},new:${request.namespace}.${request.newName}]..."
|
||||
)
|
||||
val projectModules = getProjectModules
|
||||
val packageRepository =
|
||||
ctx.executionService.getContext.getPackageRepository
|
||||
val mainPackage = packageRepository.getMainProjectPackage
|
||||
.getOrElse(throw new RenameProjectCmd.MainProjectPackageNotFound)
|
||||
val projectModules =
|
||||
packageRepository.getModulesForLibrary(mainPackage.libraryName)
|
||||
|
||||
val oldConfig = mainPackage.getConfig()
|
||||
val newConfig = mainPackage
|
||||
.reloadConfig()
|
||||
.fold(
|
||||
cause => throw new RenameProjectCmd.FailedToReloadConfig(cause),
|
||||
identity
|
||||
)
|
||||
|
||||
projectModules.foreach { module =>
|
||||
module.setIndexed(false)
|
||||
val newConfig = module.getPackage.reloadConfig()
|
||||
if (newConfig.isFailure) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
s"Failed to reload package's config: ${newConfig.failed.get.getMessage}"
|
||||
)
|
||||
}
|
||||
ctx.endpoint.sendToClient(
|
||||
Api.Response(
|
||||
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||
@ -76,11 +82,32 @@ class RenameProjectCmd(
|
||||
clearCache(stack)
|
||||
}
|
||||
|
||||
reply(Api.ProjectRenamed(request.namespace, request.newName))
|
||||
reply(
|
||||
Api.ProjectRenamed(
|
||||
oldConfig.moduleName,
|
||||
newConfig.moduleName,
|
||||
newConfig.name
|
||||
)
|
||||
)
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
s"Project renamed to ${request.namespace}.${request.newName}"
|
||||
)
|
||||
} catch {
|
||||
case ex: RenameProjectCmd.MainProjectPackageNotFound =>
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"Main project package is not found.",
|
||||
ex
|
||||
)
|
||||
reply(Api.ProjectRenameFailed(request.oldName, request.newName))
|
||||
case ex: RenameProjectCmd.FailedToReloadConfig =>
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"Failed to reload package config.",
|
||||
ex
|
||||
)
|
||||
reply(Api.ProjectRenameFailed(request.oldName, request.newName))
|
||||
} finally {
|
||||
ctx.locking.releaseWriteCompilationLock()
|
||||
logger.log(
|
||||
@ -133,13 +160,6 @@ class RenameProjectCmd(
|
||||
}
|
||||
}
|
||||
|
||||
private def getProjectModules(implicit ctx: RuntimeContext): Seq[Module] = {
|
||||
val packageRepository = ctx.executionService.getContext.getPackageRepository
|
||||
packageRepository.getMainProjectPackage
|
||||
.map { pkg => packageRepository.getModulesForLibrary(pkg.libraryName) }
|
||||
.getOrElse(List())
|
||||
}
|
||||
|
||||
private def clearCache(stack: Iterable[InstrumentFrame]): Unit = {
|
||||
stack.foreach(_.syncState.clearMethodPointersState())
|
||||
CacheInvalidation.run(
|
||||
@ -152,3 +172,12 @@ class RenameProjectCmd(
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object RenameProjectCmd {
|
||||
|
||||
final private class MainProjectPackageNotFound
|
||||
extends Exception("Main project package is not found.")
|
||||
|
||||
final private class FailedToReloadConfig(cause: Throwable)
|
||||
extends Exception("Failed to reload config", cause)
|
||||
}
|
||||
|
@ -5604,7 +5604,7 @@ class RuntimeServerTest
|
||||
)
|
||||
val renameProjectResponses = context.receiveN(6)
|
||||
renameProjectResponses should contain allOf (
|
||||
Api.Response(requestId, Api.ProjectRenamed("Enso_Test", "Foo")),
|
||||
Api.Response(requestId, Api.ProjectRenamed("Test", "Foo", "Foo")),
|
||||
context.Main.Update.mainX(contextId, typeChanged = false),
|
||||
TestMessages.update(
|
||||
contextId,
|
||||
@ -5720,7 +5720,7 @@ class RuntimeServerTest
|
||||
)
|
||||
val renameProjectResponses = context.receiveN(6)
|
||||
renameProjectResponses should contain allOf (
|
||||
Api.Response(requestId, Api.ProjectRenamed("Enso_Test", "Foo")),
|
||||
Api.Response(requestId, Api.ProjectRenamed("Test", "Foo", "Foo")),
|
||||
context.Main.Update.mainX(contextId, typeChanged = false),
|
||||
TestMessages.update(
|
||||
contextId,
|
||||
|
@ -728,7 +728,7 @@ class RuntimeSuggestionUpdatesTest
|
||||
Api.Request(requestId, Api.RenameProject("Enso_Test", "Test", "Foo"))
|
||||
)
|
||||
context.receiveN(4) should contain theSameElementsAs Seq(
|
||||
Api.Response(requestId, Api.ProjectRenamed("Enso_Test", "Foo")),
|
||||
Api.Response(requestId, Api.ProjectRenamed("Test", "Foo", "Foo")),
|
||||
Api.Response(
|
||||
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||
module = moduleName,
|
||||
|
@ -93,7 +93,7 @@ public final class ImportExportCache extends Cache<ImportExportCache.CachedBindi
|
||||
var distribution = context.getDistributionManager();
|
||||
var pathSegments = new String[]{
|
||||
pkg.namespace(),
|
||||
pkg.module(),
|
||||
pkg.normalizedName(),
|
||||
pkg.getConfig().version(),
|
||||
Info.ensoVersion(),
|
||||
libraryName.namespace()
|
||||
|
@ -112,7 +112,7 @@ public final class ModuleCache extends Cache<ModuleCache.CachedModule, ModuleCac
|
||||
var pathSegmentsJava = new ArrayList<String>();
|
||||
pathSegmentsJava.addAll(Arrays.asList(
|
||||
pkg.namespace(),
|
||||
pkg.module(),
|
||||
pkg.normalizedName(),
|
||||
pkg.getConfig().version(),
|
||||
Info.ensoVersion()
|
||||
));
|
||||
|
@ -85,7 +85,6 @@ public final class SuggestionsCache
|
||||
.map(pkg -> computeDigestOfLibrarySources(pkg.listSourcesJava(), logger));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Optional<Roots> getCacheRoots(EnsoContext context) {
|
||||
return context.getPackageRepository().getPackageForLibraryJava(libraryName).map(pkg -> {
|
||||
@ -94,7 +93,7 @@ public final class SuggestionsCache
|
||||
var distribution = context.getDistributionManager();
|
||||
var pathSegments = new String[]{
|
||||
pkg.namespace(),
|
||||
pkg.module(),
|
||||
pkg.normalizedName(),
|
||||
pkg.getConfig().version(),
|
||||
Info.ensoVersion(),
|
||||
libraryName.namespace()
|
||||
|
@ -193,26 +193,28 @@ class Compiler(
|
||||
CompletableFuture.completedFuture(false)
|
||||
case Some(pkg) =>
|
||||
val packageModule = packageRepository.getModuleMap.get(
|
||||
s"${pkg.namespace}.${pkg.module}.Main"
|
||||
s"${pkg.namespace}.${pkg.normalizedName}.Main"
|
||||
)
|
||||
packageModule match {
|
||||
case None =>
|
||||
context.log(
|
||||
Level.SEVERE,
|
||||
"Could not find entry point for compilation in package [{0}.{1}]",
|
||||
Array(pkg.namespace, pkg.module)
|
||||
Array(pkg.namespace, pkg.normalizedName)
|
||||
)
|
||||
CompletableFuture.completedFuture(false)
|
||||
case Some(m) =>
|
||||
context.log(
|
||||
Compiler.defaultLogLevel,
|
||||
s"Compiling the package [${pkg.namespace}.${pkg.module}] " +
|
||||
s"Compiling the package [${pkg.namespace}.${pkg.normalizedName}] " +
|
||||
s"starting at the root [${m.getName}]."
|
||||
)
|
||||
|
||||
val packageModules = packageRepository.freezeModuleMap.collect {
|
||||
case (name, mod)
|
||||
if name.startsWith(s"${pkg.namespace}.${pkg.module}") =>
|
||||
if name.startsWith(
|
||||
s"${pkg.namespace}.${pkg.normalizedName}"
|
||||
) =>
|
||||
mod
|
||||
}.toList
|
||||
|
||||
|
@ -129,7 +129,7 @@ case object Imports extends IRPass {
|
||||
)
|
||||
val pkgName =
|
||||
IR.Name.Literal(
|
||||
pkg.module,
|
||||
pkg.normalizedName,
|
||||
isMethod = false,
|
||||
location = None
|
||||
)
|
||||
|
@ -327,7 +327,7 @@ private class DefaultPackageRepository(
|
||||
Left(PackageRepository.Error.PackageLoadingError(err.getMessage()))
|
||||
case Right(componentGroups) =>
|
||||
logger.debug(
|
||||
s"Resolving component groups of package [${pkg.module}]."
|
||||
s"Resolving component groups of package [${pkg.normalizedName}]."
|
||||
)
|
||||
|
||||
registerComponentGroups(pkg.libraryName, componentGroups.newGroups)
|
||||
|
@ -43,7 +43,7 @@ class LibraryDownloadTest
|
||||
}
|
||||
val pkg =
|
||||
PackageManager.Default.loadPackage(libPath.location.toFile).get
|
||||
pkg.module shouldEqual "Bar"
|
||||
pkg.normalizedName shouldEqual "Bar"
|
||||
val sources = pkg.listSources()
|
||||
sources should have size 1
|
||||
sources.head.file.getName shouldEqual "Main.enso"
|
||||
|
@ -67,7 +67,7 @@ class LibraryUploadTest
|
||||
PackageManager.Default
|
||||
.loadPackage(libRoot.toFile)
|
||||
.get
|
||||
.module shouldEqual libraryName.name
|
||||
.normalizedName shouldEqual libraryName.name
|
||||
assert(Files.exists(libRoot.resolve("manifest.yaml")))
|
||||
assert(Files.exists(libRoot.resolve("main.tgz")))
|
||||
|
||||
@ -83,7 +83,7 @@ class LibraryUploadTest
|
||||
val pkg = PackageManager.Default
|
||||
.loadPackage(installedRoot.location.toFile)
|
||||
.get
|
||||
pkg.module shouldEqual libraryName.name
|
||||
pkg.normalizedName shouldEqual libraryName.name
|
||||
val sources = pkg.listSources()
|
||||
sources should have size 1
|
||||
sources.head.file.getName shouldEqual "Main.enso"
|
||||
|
@ -181,16 +181,16 @@ class Package[F](
|
||||
*/
|
||||
def name: String = config.name
|
||||
|
||||
/** Returns the module of this package.
|
||||
* @return the module of this package.
|
||||
/** Returns the normalized name of this package.
|
||||
* @return the normalized name of this package.
|
||||
*/
|
||||
def module: String =
|
||||
def normalizedName: String =
|
||||
config.normalizedName.getOrElse(NameValidation.normalizeName(name))
|
||||
|
||||
def namespace: String = config.namespace
|
||||
|
||||
/** A [[LibraryName]] associated with the package. */
|
||||
def libraryName: LibraryName = LibraryName(config.namespace, module)
|
||||
def libraryName: LibraryName = LibraryName(config.namespace, normalizedName)
|
||||
|
||||
/** Parses a file path into a qualified module name belonging to this
|
||||
* package.
|
||||
@ -202,7 +202,10 @@ class Package[F](
|
||||
val segments = sourceDir.relativize(file).getSegments.asScala.toList
|
||||
val dirSegments = segments.take(segments.length - 1)
|
||||
val fileNameWithoutExtension = file.getName.takeWhile(_ != '.')
|
||||
QualifiedName(namespace :: module :: dirSegments, fileNameWithoutExtension)
|
||||
QualifiedName(
|
||||
namespace :: normalizedName :: dirSegments,
|
||||
fileNameWithoutExtension
|
||||
)
|
||||
}
|
||||
|
||||
/** Lists the source files in this package.
|
||||
|
@ -106,7 +106,7 @@ class ProjectFileRepository[
|
||||
Project(
|
||||
id = meta.id,
|
||||
name = pkg.name,
|
||||
module = pkg.module,
|
||||
module = pkg.normalizedName,
|
||||
namespace = pkg.namespace,
|
||||
kind = meta.kind,
|
||||
created = meta.created,
|
||||
|
@ -18,7 +18,7 @@ class Project(
|
||||
def edition: Option[Editions.RawEdition] = pkg.getConfig().edition
|
||||
|
||||
/** The package name of the project. */
|
||||
def name: String = pkg.module
|
||||
def name: String = pkg.normalizedName
|
||||
|
||||
/** The path to the content root of the project. */
|
||||
def path: Path = pkg.root.toPath
|
||||
|
Loading…
Reference in New Issue
Block a user