Fix opening .enso-project files

This commit is contained in:
somebody1234 2024-06-27 01:55:07 +10:00
parent 0039c4d6a3
commit ad89effb5e
5 changed files with 108 additions and 19 deletions

View File

@ -34,7 +34,7 @@ const DEFAULT_IMPORT_ONLY_MODULES =
'@vitejs\\u002Fplugin-react|node:process|chalk|string-length|yargs|yargs\\u002Fyargs|sharp|to-ico|connect|morgan|serve-static|tiny-invariant|clsx|create-servers|electron-is-dev|fast-glob|esbuild-plugin-.+|opener|tailwindcss.*|enso-assets.*|@modyfi\\u002Fvite-plugin-yaml|is-network-error|validator.+|.*[.]json$'
const OUR_MODULES = 'enso-.*'
const RELATIVE_MODULES =
'bin\\u002Fproject-manager|bin\\u002Fserver|config\\u002Fparser|authentication|config|debug|detect|file-associations|index|ipc|log|naming|paths|preload|project-management|security|url-associations|#\\u002F.*'
'bin\\u002Fproject-manager|bin\\u002Fserver|config\\u002Fparser|authentication|config|debug|desktop-environment|detect|file-associations|index|ipc|log|naming|paths|preload|project-management|security|url-associations|#\\u002F.*'
const ALLOWED_DEFAULT_IMPORT_MODULES = `${DEFAULT_IMPORT_ONLY_MODULES}|postcss|ajv\\u002Fdist\\u002F2020|${RELATIVE_MODULES}`
const STRING_LITERAL = ':matches(Literal[raw=/^["\']/], TemplateLiteral)'
const NOT_CAMEL_CASE = '/^(?!_?[a-z][a-z0-9*]*([A-Z0-9][a-z0-9]*)*$)(?!React$)/'

View File

@ -16,7 +16,7 @@ import * as common from 'enso-common'
import GLOBAL_CONFIG from 'enso-common/src/config.json' assert { type: 'json' }
import * as contentConfig from 'enso-content-config'
import * as ydocServer from 'enso-gui2/ydoc-server'
import * as projectManagement from 'enso-project-manager-shim/src/projectManagement'
import * as projectManagement from 'project-management'
import * as paths from '../paths'

View File

@ -0,0 +1,81 @@
/**
* @file This module contains the logic for the detection of user-specific desktop environment attributes.
*/
import * as childProcess from 'node:child_process'
import * as os from 'node:os'
import * as path from 'node:path'
export const DOCUMENTS = getDocumentsPath()
const CHILD_PROCESS_TIMEOUT = 3000
/**
* Detects path of the user documents directory depending on the operating system.
*/
function getDocumentsPath(): string | undefined {
if (process.platform === 'linux') {
return getLinuxDocumentsPath()
} else if (process.platform === 'darwin') {
return getMacOsDocumentsPath()
} else if (process.platform === 'win32') {
return getWindowsDocumentsPath()
} else {
return
}
}
/**
* Returns the user documents path on Linux.
*/
function getLinuxDocumentsPath(): string {
const xdgDocumentsPath = getXdgDocumentsPath()
return xdgDocumentsPath ?? path.join(os.homedir(), 'enso')
}
/**
* Gets the documents directory from the XDG directory management system.
*/
function getXdgDocumentsPath(): string | undefined {
const out = childProcess.spawnSync('xdg-user-dir', ['DOCUMENTS'], {
timeout: CHILD_PROCESS_TIMEOUT,
})
if (out.error !== undefined) {
return
} else {
return out.stdout.toString().trim()
}
}
/**
* Get the user documents path. On macOS, `Documents` acts as a symlink pointing to the
* real locale-specific user documents directory.
*/
function getMacOsDocumentsPath(): string {
return path.join(os.homedir(), 'Documents')
}
/**
* Get the path to the `My Documents` Windows directory.
*/
function getWindowsDocumentsPath(): string | undefined {
const out = childProcess.spawnSync(
'reg',
[
'query',
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders',
'/v',
'personal',
],
{ timeout: CHILD_PROCESS_TIMEOUT }
)
if (out.error !== undefined) {
return
} else {
const stdoutString = out.stdout.toString()
return stdoutString.split(/\s\s+/)[4]
}
}

View File

@ -7,23 +7,28 @@
* - if the project is in a different location, we copy it to the Project Manager's location
* and open it.
* - if the project is a bundle, we extract it to the Project Manager's location and open it. */
import * as crypto from 'node:crypto'
import * as fs from 'node:fs'
import * as os from 'node:os'
import * as pathModule from 'node:path'
import type * as stream from 'node:stream'
import * as electron from 'electron'
import * as tar from 'tar'
import * as common from 'enso-common'
import * as buildUtils from 'enso-common/src/buildUtils'
import * as config from 'enso-content-config'
import * as desktopEnvironment from 'desktop-environment'
import * as paths from 'paths'
import * as fileAssociations from '../file-associations'
const logger = console
const logger = config.logger
// =================
// === Constants ===
// =================
export const PACKAGE_METADATA_RELATIVE_PATH = 'package.yaml'
export const PROJECT_METADATA_RELATIVE_PATH = '.enso/project.json'
/** The filename suffix for the project bundle, including the leading period character. */
const BUNDLED_PROJECT_SUFFIX = '.enso-project'
// ======================
// === Project Import ===
@ -40,7 +45,7 @@ export function importProjectFromPath(
name: string | null = null
): string {
directory ??= getProjectsDirectory()
if (pathModule.extname(openedPath).endsWith(fileAssociations.BUNDLED_PROJECT_SUFFIX)) {
if (pathModule.extname(openedPath).endsWith(BUNDLED_PROJECT_SUFFIX)) {
logger.log(`Path '${openedPath}' denotes a bundled project.`)
// The second part of condition is for the case when someone names a directory
// like `my-project.enso-project` and stores the project there.
@ -52,7 +57,7 @@ export function importProjectFromPath(
return importBundle(openedPath, directory, name)
}
} else {
logger.log(`Opening non-bundled file '${openedPath}'.`)
logger.log(`Opening non-bundled file: '${openedPath}'.`)
const rootPath = getProjectRoot(openedPath)
// Check if the project root is under the projects directory. If it is, we can open it.
// Otherwise, we need to install it first.
@ -228,7 +233,7 @@ export function getProjectId(projectRoot: string): string | null {
/** Update the package name. */
export function updatePackageName(projectRoot: string, name: string) {
const path = pathModule.join(projectRoot, paths.PACKAGE_METADATA_RELATIVE)
const path = pathModule.join(projectRoot, PACKAGE_METADATA_RELATIVE_PATH)
const contents = fs.readFileSync(path, { encoding: 'utf-8' })
const newContents = contents.replace(/^name: .*/, `name: ${name}`)
fs.writeFileSync(path, newContents)
@ -246,7 +251,7 @@ export function createMetadata(): ProjectMetadata {
/** Retrieve the project's metadata. */
export function getMetadata(projectRoot: string): ProjectMetadata | null {
const metadataPath = pathModule.join(projectRoot, paths.PROJECT_METADATA_RELATIVE)
const metadataPath = pathModule.join(projectRoot, PROJECT_METADATA_RELATIVE_PATH)
try {
const jsonText = fs.readFileSync(metadataPath, 'utf8')
const metadata: unknown = JSON.parse(jsonText)
@ -258,7 +263,7 @@ export function getMetadata(projectRoot: string): ProjectMetadata | null {
/** Write the project's metadata. */
export function writeMetadata(projectRoot: string, metadata: ProjectMetadata): void {
const metadataPath = pathModule.join(projectRoot, paths.PROJECT_METADATA_RELATIVE)
const metadataPath = pathModule.join(projectRoot, PROJECT_METADATA_RELATIVE_PATH)
fs.mkdirSync(pathModule.dirname(metadataPath), { recursive: true })
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, buildUtils.INDENT_SIZE))
}
@ -284,7 +289,7 @@ export function updateMetadata(
/** Check if the given path represents the root of an Enso project.
* This is decided by the presence of the Project Manager's metadata. */
export function isProjectRoot(candidatePath: string): boolean {
const projectJsonPath = pathModule.join(candidatePath, paths.PROJECT_METADATA_RELATIVE)
const projectJsonPath = pathModule.join(candidatePath, PROJECT_METADATA_RELATIVE_PATH)
try {
fs.accessSync(projectJsonPath, fs.constants.R_OK)
return true
@ -365,7 +370,12 @@ export function getProjectRoot(subtreePath: string): string | null {
/** Get the directory that stores Enso projects. */
export function getProjectsDirectory(): string {
return pathModule.join(electron.app.getPath('home'), 'enso', 'projects')
const documentsPath = desktopEnvironment.DOCUMENTS
if (documentsPath === undefined) {
return pathModule.join(os.homedir(), 'enso', 'projects')
} else {
return pathModule.join(documentsPath, 'enso-projects')
}
}
/** Check if the given project is installed, i.e. can be opened with the Project Manager. */
@ -387,11 +397,9 @@ export function generateId(): string {
return crypto.randomUUID()
}
/** Update the project's ID to a new, unique value, and its last opened date to the current date.
* Return the new ID. */
/** Update the project's ID to a new, unique value, and its last opened date to the current date. */
export function bumpMetadata(projectRoot: string, name: string | null): string {
if (name != null) {
console.log('nom', name)
updatePackageName(projectRoot, name)
}
return updateMetadata(projectRoot, metadata => ({

View File

@ -28,7 +28,7 @@ const logger = console
export const PACKAGE_METADATA_RELATIVE_PATH = 'package.yaml'
export const PROJECT_METADATA_RELATIVE_PATH = '.enso/project.json'
/** The filename suffix for the project bundle, including the leading period character. */
const BUNDLED_PROJECT_SUFFIX = `.enso-project`
const BUNDLED_PROJECT_SUFFIX = '.enso-project'
// ======================
// === Project Import ===