第一次
This commit is contained in:
28
.babelrc
28
.babelrc
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@babel/plugin-proposal-class-properties"
|
"@babel/plugin-proposal-class-properties"
|
||||||
],
|
],
|
||||||
"presets": [
|
"presets": [
|
||||||
[
|
[
|
||||||
"@babel/preset-env",
|
"@babel/preset-env",
|
||||||
{
|
{
|
||||||
"targets": {
|
"targets": {
|
||||||
"node": "12"
|
"node": "12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
@@ -1,25 +1,25 @@
|
|||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
|
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
|
||||||
{
|
{
|
||||||
"name": "Node.js & TypeScript",
|
"name": "Node.js & TypeScript",
|
||||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
|
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/git:1": {}
|
"ghcr.io/devcontainers/features/git:1": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
// "features": {},
|
// "features": {},
|
||||||
|
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
// "forwardPorts": [],
|
// "forwardPorts": [],
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
"postCreateCommand": "npm install"
|
"postCreateCommand": "npm install"
|
||||||
|
|
||||||
// Configure tool-specific properties.
|
// Configure tool-specific properties.
|
||||||
// "customizations": {},
|
// "customizations": {},
|
||||||
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
// "remoteUser": "root"
|
// "remoteUser": "root"
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
!.eslintrc.js
|
!.eslintrc.js
|
||||||
/node_modules/**
|
/node_modules/**
|
||||||
/lib/**
|
/lib/**
|
||||||
|
@@ -1,30 +1,33 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 6,
|
"ecmaVersion": 6,
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint"
|
"@typescript-eslint"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/naming-convention": [
|
"@typescript-eslint/naming-convention": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
"selector": "import",
|
"selector": "import",
|
||||||
"format": [ "camelCase", "PascalCase" ]
|
"format": [
|
||||||
}
|
"camelCase",
|
||||||
],
|
"PascalCase"
|
||||||
"@typescript-eslint/semi": "warn",
|
]
|
||||||
"curly": "warn",
|
}
|
||||||
"eqeqeq": "warn",
|
],
|
||||||
"no-throw-literal": "warn",
|
"@typescript-eslint/semi": "off", //关闭分号检查
|
||||||
"semi": "off"
|
"curly": "warn",
|
||||||
},
|
"eqeqeq": "warn",
|
||||||
"ignorePatterns": [
|
"no-throw-literal": "warn",
|
||||||
"out",
|
"semi": "off"
|
||||||
"dist",
|
},
|
||||||
"**/*.d.ts"
|
"ignorePatterns": [
|
||||||
]
|
"out",
|
||||||
|
"dist",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
16
.gitignore
vendored
16
.gitignore
vendored
@@ -1,9 +1,9 @@
|
|||||||
/node_modules/
|
/node_modules/
|
||||||
/dist
|
/dist
|
||||||
*.vsix
|
*.vsix
|
||||||
yarn.lock
|
yarn.lock
|
||||||
package-lock.json
|
package-lock.json
|
||||||
*.dict
|
*.dict
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
/tmp
|
/tmp
|
52
.vscode/launch.json
vendored
52
.vscode/launch.json
vendored
@@ -1,26 +1,26 @@
|
|||||||
// A launch configuration that launches the extension inside a new window
|
// A launch configuration that launches the extension inside a new window
|
||||||
{
|
{
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Launch Extension",
|
"name": "Launch Extension",
|
||||||
"type": "extensionHost",
|
"type": "extensionHost",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
|
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"preLaunchTask": "npm: build",
|
"preLaunchTask": "npm: build",
|
||||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Launch Tests",
|
"name": "Launch Tests",
|
||||||
"type": "extensionHost",
|
"type": "extensionHost",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"runtimeExecutable": "${execPath}",
|
"runtimeExecutable": "${execPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--extensionDevelopmentPath=${workspaceRoot}",
|
"--extensionDevelopmentPath=${workspaceRoot}",
|
||||||
"--extensionTestsPath=${workspaceRoot}/test"
|
"--extensionTestsPath=${workspaceRoot}/test"
|
||||||
],
|
],
|
||||||
"preLaunchTask": "npm: build",
|
"preLaunchTask": "npm: build",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
66
.vscode/tasks.json
vendored
66
.vscode/tasks.json
vendored
@@ -1,34 +1,34 @@
|
|||||||
{
|
{
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "build",
|
"script": "build",
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"label": "npm: build",
|
"label": "npm: build",
|
||||||
"detail": "webpack --mode production"
|
"detail": "webpack --mode production"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "package",
|
"script": "package",
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"label": "npm: package",
|
"label": "npm: package",
|
||||||
"detail": "webpack --mode production && vsce package"
|
"detail": "webpack --mode production && vsce package"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "watch",
|
"script": "watch",
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"label": "npm: watch",
|
"label": "npm: watch",
|
||||||
"detail": "webpack --mode production --watch"
|
"detail": "webpack --mode production --watch"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "format",
|
"script": "format",
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"label": "npm: format",
|
"label": "npm: format",
|
||||||
"detail": "eslint src --ext ts"
|
"detail": "eslint src --ext ts"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
.vscode/**
|
.vscode/**
|
||||||
.vscode-test/**
|
.vscode-test/**
|
||||||
src/**
|
src/**
|
||||||
test/**
|
test/**
|
||||||
.babelrc
|
.babelrc
|
||||||
.eslintignore
|
.eslintignore
|
||||||
.eslintrc.js
|
.eslintrc.js
|
||||||
.gitignore
|
.gitignore
|
||||||
|
72
README.en.md
72
README.en.md
@@ -1,36 +1,36 @@
|
|||||||
# DevStar
|
# DevStar
|
||||||
|
|
||||||
#### Description
|
#### Description
|
||||||
Super IDE Client for VS Code
|
Super IDE Client for VS Code
|
||||||
|
|
||||||
#### Software Architecture
|
#### Software Architecture
|
||||||
Software architecture description
|
Software architecture description
|
||||||
|
|
||||||
#### Installation
|
#### Installation
|
||||||
|
|
||||||
1. xxxx
|
1. xxxx
|
||||||
2. xxxx
|
2. xxxx
|
||||||
3. xxxx
|
3. xxxx
|
||||||
|
|
||||||
#### Instructions
|
#### Instructions
|
||||||
|
|
||||||
1. xxxx
|
1. xxxx
|
||||||
2. xxxx
|
2. xxxx
|
||||||
3. xxxx
|
3. xxxx
|
||||||
|
|
||||||
#### Contribution
|
#### Contribution
|
||||||
|
|
||||||
1. Fork the repository
|
1. Fork the repository
|
||||||
2. Create Feat_xxx branch
|
2. Create Feat_xxx branch
|
||||||
3. Commit your code
|
3. Commit your code
|
||||||
4. Create Pull Request
|
4. Create Pull Request
|
||||||
|
|
||||||
|
|
||||||
#### Gitee Feature
|
#### Gitee Feature
|
||||||
|
|
||||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||||
|
166
README.md
166
README.md
@@ -1,84 +1,84 @@
|
|||||||
# DevStar
|
# DevStar
|
||||||
|
|
||||||
## User Quick Start
|
## User Quick Start
|
||||||
|
|
||||||
进入home页面,home页面的功能都需要登录后才能使用。
|
进入home页面,home页面的功能都需要登录后才能使用。
|
||||||
|
|
||||||
登录后,登录状态会长久保存,直到主动退出登录或者卸载插件。
|
登录后,登录状态会长久保存,直到主动退出登录或者卸载插件。
|
||||||
|
|
||||||
### 可供配置的字段
|
### 可供配置的字段
|
||||||
|
|
||||||
- Devstar Domain(注意点:`https://devstar.cn`和`http://localhost:3000`的协议头`https`和`http`不能写错或写反,否则会出现页面无反应的异常。)
|
- Devstar Domain(注意点:`https://devstar.cn`和`http://localhost:3000`的协议头`https`和`http`不能写错或写反,否则会出现页面无反应的异常。)
|
||||||
|
|
||||||
注意:
|
注意:
|
||||||
|
|
||||||
1)配置修改后,重启vscode才能生效;
|
1)配置修改后,重启vscode才能生效;
|
||||||
|
|
||||||
### 创建新仓库/创建新项目
|
### 创建新仓库/创建新项目
|
||||||
|
|
||||||
目前可供选择的字段
|
目前可供选择的字段
|
||||||
|
|
||||||
- name* 必填
|
- name* 必填
|
||||||
- default_branch
|
- default_branch
|
||||||
- description
|
- description
|
||||||
- gitignores
|
- gitignores
|
||||||
- issue_labels
|
- issue_labels
|
||||||
- license
|
- license
|
||||||
- object_format_name
|
- object_format_name
|
||||||
- private
|
- private
|
||||||
- readme
|
- readme
|
||||||
- template
|
- template
|
||||||
- trust_model
|
- trust_model
|
||||||
|
|
||||||
### 打开项目
|
### 打开项目
|
||||||
|
|
||||||
打开项目是指在vscode上打开远程容器中创建好的项目。选择项目名称右侧对应的Open project,即可打开项目。
|
打开项目是指在vscode上打开远程容器中创建好的项目。选择项目名称右侧对应的Open project,即可打开项目。
|
||||||
|
|
||||||
### 编译/调试
|
### 编译/调试
|
||||||
|
|
||||||
容器环境提供了开发环境,安装好编译与调试所需要的工具链。
|
容器环境提供了开发环境,安装好编译与调试所需要的工具链。
|
||||||
|
|
||||||
## Developer Quick Start
|
## Developer Quick Start
|
||||||
|
|
||||||
### 准备开发环境
|
### 准备开发环境
|
||||||
|
|
||||||
#### Windows/MacOS/Linux
|
#### Windows/MacOS/Linux
|
||||||
|
|
||||||
需要预置开发环境:Nodejs、Typescript开发环境
|
需要预置开发环境:Nodejs、Typescript开发环境
|
||||||
|
|
||||||
1. git clone项目到本地,然后通过VSCode打开项目。
|
1. git clone项目到本地,然后通过VSCode打开项目。
|
||||||
2. 下载项目所需依赖,执行命令:`npm install`。
|
2. 下载项目所需依赖,执行命令:`npm install`。
|
||||||
|
|
||||||
#### DevContainer环境
|
#### DevContainer环境
|
||||||
|
|
||||||
1. git clone项目到本地,然后通过VSCode打开项目
|
1. git clone项目到本地,然后通过VSCode打开项目
|
||||||
2. 项目提供了devcontainer的开发配置,通过vscode打开本项目后,会提示“Folder contains a Dev Container configuration file. Reopen folder to develop in a container ([learn more](https://aka.ms/vscode-remote/docker)).”,此时点击“Reopen in Container”,自动进入vscode的devcontainer环境中。
|
2. 项目提供了devcontainer的开发配置,通过vscode打开本项目后,会提示“Folder contains a Dev Container configuration file. Reopen folder to develop in a container ([learn more](https://aka.ms/vscode-remote/docker)).”,此时点击“Reopen in Container”,自动进入vscode的devcontainer环境中。
|
||||||
3. 本项目的devcontainer预置了Node.js & Typescript的开发环境。在vscode的命令行工具执行`npm install`命令,下载项目所需依赖。
|
3. 本项目的devcontainer预置了Node.js & Typescript的开发环境。在vscode的命令行工具执行`npm install`命令,下载项目所需依赖。
|
||||||
|
|
||||||
### 编译插件
|
### 编译插件
|
||||||
|
|
||||||
1. 项目目录`.vscode/launch.json`中提供了编译与启动插件的配置。
|
1. 项目目录`.vscode/launch.json`中提供了编译与启动插件的配置。
|
||||||
2. 按`F5`即可编译和测试插件。
|
2. 按`F5`即可编译和测试插件。
|
||||||
|
|
||||||
### 打包&发布插件
|
### 打包&发布插件
|
||||||
|
|
||||||
1. 打包和发布插件均需要用到`@vscode/vsce`包,项目依赖中已包含。
|
1. 打包和发布插件均需要用到`@vscode/vsce`包,项目依赖中已包含。
|
||||||
2. 打包插件
|
2. 打包插件
|
||||||
1. 方法一:通过Ctrl+Shift+P启动Command Palette,选择Tasks: Run Task,然后选择最下方的Show All Tasks...,最后选择npm: vscode:package。
|
1. 方法一:通过Ctrl+Shift+P启动Command Palette,选择Tasks: Run Task,然后选择最下方的Show All Tasks...,最后选择npm: vscode:package。
|
||||||
2. 方法二:打开package.json文件,找到`scripts`字段,它上方有`Debug`按钮,点击之后会让你选择要执行的task,选择vscode:package。
|
2. 方法二:打开package.json文件,找到`scripts`字段,它上方有`Debug`按钮,点击之后会让你选择要执行的task,选择vscode:package。
|
||||||
3. 发布插件
|
3. 发布插件
|
||||||
1. 发布之前需要先完成打包。
|
1. 发布之前需要先完成打包。
|
||||||
2. 发布插件需要publisher的Personal Access Token(token项目负责人)。(Token**有效时间**:1年)
|
2. 发布插件需要publisher的Personal Access Token(token项目负责人)。(Token**有效时间**:1年)
|
||||||
3. 发布方法
|
3. 发布方法
|
||||||
1. 方法一:步骤与打包插件的方法一基本一样,除了最后一步选择npm: vscode:publish。接着会弹出要求填写Personal Access Token的prompt,填上回车即可。
|
1. 方法一:步骤与打包插件的方法一基本一样,除了最后一步选择npm: vscode:publish。接着会弹出要求填写Personal Access Token的prompt,填上回车即可。
|
||||||
2. 方法二:步骤与打包插件的方法二基本一样,除了最后一步选择npm: vscode:publish。接着会弹出要求填写Personal Access Token的prompt,填上回车即可。
|
2. 方法二:步骤与打包插件的方法二基本一样,除了最后一步选择npm: vscode:publish。接着会弹出要求填写Personal Access Token的prompt,填上回车即可。
|
||||||
|
|
||||||
### 特殊:Git
|
### 特殊:Git
|
||||||
|
|
||||||
由于先在主机上clone下来项目,在devcontainer上再打开以后,git认为所有的文件都更改了。需要在`.git/config`添加如下的配置:
|
由于先在主机上clone下来项目,在devcontainer上再打开以后,git认为所有的文件都更改了。需要在`.git/config`添加如下的配置:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
[core]
|
[core]
|
||||||
- filemode = false
|
- filemode = false
|
||||||
- autocrlf = true
|
- autocrlf = true
|
||||||
```
|
```
|
@@ -1,44 +1,44 @@
|
|||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
`package.json`
|
`package.json`
|
||||||
|
|
||||||
- 插件基本信息
|
- 插件基本信息
|
||||||
- 插件的命令、对外开放的接口
|
- 插件的命令、对外开放的接口
|
||||||
- 插件的activity bar、status bar
|
- 插件的activity bar、status bar
|
||||||
- scripts
|
- scripts
|
||||||
- 项目配置、依赖
|
- 项目配置、依赖
|
||||||
|
|
||||||
`tsconfig.json`、`webpack.config.js`
|
`tsconfig.json`、`webpack.config.js`
|
||||||
|
|
||||||
- ts编译为js的配置
|
- ts编译为js的配置
|
||||||
|
|
||||||
assets目录
|
assets目录
|
||||||
|
|
||||||
- 静态资源
|
- 静态资源
|
||||||
|
|
||||||
源文件
|
源文件
|
||||||
|
|
||||||
- `main.ts`:负责构建插件、构建插件过程的操作,activate/deactivate插件
|
- `main.ts`:负责构建插件、构建插件过程的操作,activate/deactivate插件
|
||||||
- `home.ts`:负责与home页面相关的操作,如构建home页面(webview)、作为home页面与vscode交互的桥梁
|
- `home.ts`:负责与home页面相关的操作,如构建home页面(webview)、作为home页面与vscode交互的桥梁
|
||||||
- home页面 - embedded.html
|
- home页面 - embedded.html
|
||||||
- views目录:负责vscode中除home页面的其他界面设计
|
- views目录:负责vscode中除home页面的其他界面设计
|
||||||
- `quick-access-tree.ts`负责左侧快速访问栏
|
- `quick-access-tree.ts`负责左侧快速访问栏
|
||||||
- `remote-container.ts`:负责与remote container相关的操作,如第一次连接容器、打开容器中的项目文件夹
|
- `remote-container.ts`:负责与remote container相关的操作,如第一次连接容器、打开容器中的项目文件夹
|
||||||
- `utils.ts`:一些通用函数
|
- `utils.ts`:一些通用函数
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.devcontainer目录
|
.devcontainer目录
|
||||||
|
|
||||||
- devcontainer相关配置
|
- devcontainer相关配置
|
||||||
|
|
||||||
.vscode目录
|
.vscode目录
|
||||||
|
|
||||||
- `launch.json`:(编译)启动插件配置
|
- `launch.json`:(编译)启动插件配置
|
||||||
|
|
||||||
|
|
||||||
## 模块
|
## 模块
|
||||||
|
|
||||||
Remote container
|
Remote container
|
||||||
|
|
||||||
Home
|
Home
|
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"Home": "主页",
|
"Home": "主页",
|
||||||
"DevStar Home": "DevStar主页",
|
"DevStar Home": "DevStar主页",
|
||||||
"Open": "打开主页",
|
"Open": "打开主页",
|
||||||
"Miscellaneous": "杂项",
|
"Miscellaneous": "杂项",
|
||||||
"Clean": "清理",
|
"Clean": "清理",
|
||||||
"User login successfully!":"用户已登录!",
|
"User login successfully!":"用户已登录!",
|
||||||
"User has logged out!":"用户已登出!",
|
"User has logged out!":"用户已登出!",
|
||||||
"Installing vscode-server and devstar extension in container": "正在容器中安装vscode-server及devstar插件",
|
"Installing vscode-server and devstar extension in container": "正在容器中安装vscode-server及devstar插件",
|
||||||
"Connected! Start installation": "连接成功,开始安装",
|
"Connected! Start installation": "连接成功,开始安装",
|
||||||
"Installation completed!": "安装完成!",
|
"Installation completed!": "安装完成!",
|
||||||
"Project has been open!": "该项目已经打开!"
|
"Project has been open!": "该项目已经打开!"
|
||||||
}
|
}
|
278
package.json
278
package.json
@@ -1,139 +1,139 @@
|
|||||||
{
|
{
|
||||||
"name": "devstar",
|
"name": "devstar",
|
||||||
"displayName": "%displayName%",
|
"displayName": "%displayName%",
|
||||||
"description": "%description%",
|
"description": "%description%",
|
||||||
"version": "0.3.8",
|
"version": "0.3.8",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"publisher": "mengning",
|
"publisher": "mengning",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.75.0"
|
"vscode": "^1.75.0"
|
||||||
},
|
},
|
||||||
"l10n": "./l10n",
|
"l10n": "./l10n",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"categories": [],
|
"categories": [],
|
||||||
"main": "./dist/extension",
|
"main": "./dist/extension",
|
||||||
"icon": "assets/images/devstar-logo.png",
|
"icon": "assets/images/devstar-logo.png",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/mengning/DevStar/issues"
|
"url": "https://github.com/mengning/DevStar/issues"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/mengning/DevStar.git"
|
"url": "https://github.com/mengning/DevStar.git"
|
||||||
},
|
},
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
"onView:devstar.quickAccess",
|
"onView:devstar.quickAccess",
|
||||||
"onCommand:devstar.showHome",
|
"onCommand:devstar.showHome",
|
||||||
"onUri"
|
"onUri"
|
||||||
],
|
],
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"command": "devstar.showHome",
|
"command": "devstar.showHome",
|
||||||
"title": "%devstar.showHome.title%",
|
"title": "%devstar.showHome.title%",
|
||||||
"category": "DevStar"
|
"category": "DevStar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "devstar.connectRemoteContainer",
|
"command": "devstar.connectRemoteContainer",
|
||||||
"title": "%devstar.connectRemoteContainer.title%",
|
"title": "%devstar.connectRemoteContainer.title%",
|
||||||
"category": "DevStar"
|
"category": "DevStar"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uriHandlers": [
|
"uriHandlers": [
|
||||||
{
|
{
|
||||||
"protocol": "vscode",
|
"protocol": "vscode",
|
||||||
"path": "/openProject"
|
"path": "/openProject"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"views": {
|
"views": {
|
||||||
"devstarListView": [
|
"devstarListView": [
|
||||||
{
|
{
|
||||||
"id": "devstar.quickAccess",
|
"id": "devstar.quickAccess",
|
||||||
"name": "%devstar.quickAccess.title%",
|
"name": "%devstar.quickAccess.title%",
|
||||||
"type": "tree"
|
"type": "tree"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"viewsContainers": {
|
"viewsContainers": {
|
||||||
"activitybar": [
|
"activitybar": [
|
||||||
{
|
{
|
||||||
"id": "devstarListView",
|
"id": "devstarListView",
|
||||||
"title": "%devstar.devstar.title%",
|
"title": "%devstar.devstar.title%",
|
||||||
"icon": "assets/icons/devstar-activity-icon.svg"
|
"icon": "assets/icons/devstar-activity-icon.svg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"viewsWelcome": [
|
"viewsWelcome": [
|
||||||
{
|
{
|
||||||
"view": "devstar.quickAccess",
|
"view": "devstar.quickAccess",
|
||||||
"contents": "%devstar.welcome.title%"
|
"contents": "%devstar.welcome.title%"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
"file/newFile": [
|
"file/newFile": [
|
||||||
{
|
{
|
||||||
"command": "devstar.showHome",
|
"command": "devstar.showHome",
|
||||||
"group": "navigation"
|
"group": "navigation"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"touchBar": []
|
"touchBar": []
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "DevStar",
|
"title": "DevStar",
|
||||||
"properties": {
|
"properties": {
|
||||||
"devstar.disableDevStarHomeStartup": {
|
"devstar.disableDevStarHomeStartup": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Disable showing DevStar Home at startup"
|
"description": "Disable showing DevStar Home at startup"
|
||||||
},
|
},
|
||||||
"devstar.devstarDomain": {
|
"devstar.devstarDomain": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "https://devstar.cn/",
|
"default": "https://devstar.cn/",
|
||||||
"description": "DevStar Domain URL"
|
"description": "DevStar Domain URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --mode production",
|
"build": "webpack --mode production",
|
||||||
"package": "webpack --mode production && vsce package",
|
"package": "webpack --mode production && vsce package",
|
||||||
"publish": "vsce publish",
|
"publish": "vsce publish",
|
||||||
"watch": "webpack --mode production --watch",
|
"watch": "webpack --mode production --watch",
|
||||||
"format": "eslint src --ext ts"
|
"format": "eslint src --ext ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
"fs-plus": "~3.1.1",
|
"fs-plus": "~3.1.1",
|
||||||
"node-ssh": "^13.2.0",
|
"node-ssh": "^13.2.0",
|
||||||
"semver": "^7.7.2",
|
"semver": "^7.7.2",
|
||||||
"sshpk": "^1.18.0"
|
"sshpk": "^1.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "~7.21.3",
|
"@babel/core": "~7.21.3",
|
||||||
"@babel/eslint-parser": "~7.21.3",
|
"@babel/eslint-parser": "~7.21.3",
|
||||||
"@babel/plugin-proposal-class-properties": "~7.18.6",
|
"@babel/plugin-proposal-class-properties": "~7.18.6",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "~7.18.9",
|
"@babel/plugin-proposal-object-rest-spread": "~7.18.9",
|
||||||
"@babel/preset-env": "~7.20.2",
|
"@babel/preset-env": "~7.20.2",
|
||||||
"@babel/preset-typescript": "^7.18.6",
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
"@types/mocha": "^10.0.6",
|
"@types/mocha": "^10.0.6",
|
||||||
"@types/node": "18.x",
|
"@types/node": "18.x",
|
||||||
"@types/vscode": "~1.75.0",
|
"@types/vscode": "~1.75.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
||||||
"@typescript-eslint/parser": "^7.11.0",
|
"@typescript-eslint/parser": "^7.11.0",
|
||||||
"@vscode/test-cli": "^0.0.9",
|
"@vscode/test-cli": "^0.0.9",
|
||||||
"@vscode/test-electron": "^2.4.0",
|
"@vscode/test-electron": "^2.4.0",
|
||||||
"@vscode/vsce": "^2.29.0",
|
"@vscode/vsce": "^2.29.0",
|
||||||
"babel-loader": "~9.1.2",
|
"babel-loader": "~9.1.2",
|
||||||
"eslint-import-resolver-webpack": "~0.13.2",
|
"eslint-import-resolver-webpack": "~0.13.2",
|
||||||
"eslint-plugin-import": "~2.27.5",
|
"eslint-plugin-import": "~2.27.5",
|
||||||
"prettier": "~2.8.4",
|
"prettier": "~2.8.4",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"webpack": "~5.76.2",
|
"webpack": "~5.76.2",
|
||||||
"webpack-cli": "~5.0.1"
|
"webpack-cli": "~5.0.1"
|
||||||
},
|
},
|
||||||
"extensionDependencies": [
|
"extensionDependencies": [
|
||||||
"ms-vscode.cpptools"
|
"ms-vscode.cpptools"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"displayName": "DevStar",
|
"displayName": "DevStar",
|
||||||
"description": "DevStar Client",
|
"description": "DevStar Client",
|
||||||
"devstar.showHome.title": "DevStar Home",
|
"devstar.showHome.title": "DevStar Home",
|
||||||
"devstar.connectRemoteContainer.title": "Connect to a Remote Container",
|
"devstar.connectRemoteContainer.title": "Connect to a Remote Container",
|
||||||
"devstar.quickAccess.title": "Quick Access",
|
"devstar.quickAccess.title": "Quick Access",
|
||||||
"devstar.devstar.title":"DevStar",
|
"devstar.devstar.title":"DevStar",
|
||||||
"devstar.welcome.title":"welcome DevStar..."
|
"devstar.welcome.title":"welcome DevStar..."
|
||||||
}
|
}
|
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"displayName": "DevStar",
|
"displayName": "DevStar",
|
||||||
"description": "DevStar客户端",
|
"description": "DevStar客户端",
|
||||||
"devstar.showHome.title": "显示主页",
|
"devstar.showHome.title": "显示主页",
|
||||||
"devstar.connectRemoteContainer.title": "连接容器",
|
"devstar.connectRemoteContainer.title": "连接容器",
|
||||||
"devstar.quickAccess.title": "快速访问",
|
"devstar.quickAccess.title": "快速访问",
|
||||||
"devstar.devstar.title":"DevStar",
|
"devstar.devstar.title":"DevStar",
|
||||||
"devstar.welcome.title":"欢迎使用DevStar..."
|
"devstar.welcome.title":"欢迎使用DevStar..."
|
||||||
}
|
}
|
@@ -1,99 +1,99 @@
|
|||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
|
||||||
import User from "./user";
|
import User from "./user";
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
|
|
||||||
export default class DevstarAPIHandler {
|
export default class DevstarAPIHandler {
|
||||||
|
|
||||||
private devstarDomain: string;
|
private devstarDomain: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// 获取domain
|
// 获取domain
|
||||||
const devstarDomainFromUserConfig = utils.devstarDomain()
|
const devstarDomainFromUserConfig = utils.devstarDomain()
|
||||||
if (undefined == devstarDomainFromUserConfig || "" == devstarDomainFromUserConfig) {
|
if (undefined == devstarDomainFromUserConfig || "" == devstarDomainFromUserConfig) {
|
||||||
this.devstarDomain = "https://devstar.cn";
|
this.devstarDomain = "https://devstar.cn";
|
||||||
} else {
|
} else {
|
||||||
this.devstarDomain = devstarDomainFromUserConfig.endsWith('/') ? devstarDomainFromUserConfig.slice(0, -1) : devstarDomainFromUserConfig;
|
this.devstarDomain = devstarDomainFromUserConfig.endsWith('/') ? devstarDomainFromUserConfig.slice(0, -1) : devstarDomainFromUserConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async verifyToken(token: string, username: string): Promise<boolean> {
|
public async verifyToken(token: string, username: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(this.devstarDomain + `/api/devcontainer/user`, {
|
const response = await fetch(this.devstarDomain + `/api/devcontainer/user`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': 'token ' + token
|
'Authorization': 'token ' + token
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理非200响应状态码
|
// 处理非200响应状态码
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const text = await response.text(); // 先读取文本防止json解析失败
|
const text = await response.text(); // 先读取文本防止json解析失败
|
||||||
if (response.status == 401) {
|
if (response.status == 401) {
|
||||||
throw new Error('Token错误')
|
throw new Error('Token错误')
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`HTTP Error: ${response.status} - ${text}`);
|
throw new Error(`HTTP Error: ${response.status} - ${text}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
const data = responseData.data
|
const data = responseData.data
|
||||||
if (data.username == undefined || data.username == "") {
|
if (data.username == undefined || data.username == "") {
|
||||||
throw new Error('Token对应用户不存在')
|
throw new Error('Token对应用户不存在')
|
||||||
} else {
|
} else {
|
||||||
// 验证用户名匹配
|
// 验证用户名匹配
|
||||||
if (data.username !== username) {
|
if (data.username !== username) {
|
||||||
throw new Error('Token与用户名不符');
|
throw new Error('Token与用户名不符');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传公钥
|
// 上传公钥
|
||||||
public async uploadUserPublicKey(user: User): Promise<string> {
|
public async uploadUserPublicKey(user: User): Promise<string> {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
// 获取机器名称
|
// 获取机器名称
|
||||||
const machineName = os.hostname();
|
const machineName = os.hostname();
|
||||||
// 组成公钥名称
|
// 组成公钥名称
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
const keyTitle = `${user.getUsernameFromLocal()}-${machineName}-${timestamp}`
|
const keyTitle = `${user.getUsernameFromLocal()}-${machineName}-${timestamp}`
|
||||||
const postData = {
|
const postData = {
|
||||||
"key": user.getUserPublicKey(),
|
"key": user.getUserPublicKey(),
|
||||||
"title": keyTitle
|
"title": keyTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadUrl = this.devstarDomain + `/api/v1/user/keys`
|
const uploadUrl = this.devstarDomain + `/api/v1/user/keys`
|
||||||
|
|
||||||
// 上传公钥
|
// 上传公钥
|
||||||
fetch(uploadUrl, {
|
fetch(uploadUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': 'token ' + user.getUserTokenFromLocal()
|
'Authorization': 'token ' + user.getUserTokenFromLocal()
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData)
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
response.json().then(data => {
|
response.json().then(data => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
console.log("Successfully upload new created public key.\n", data)
|
console.log("Successfully upload new created public key.\n", data)
|
||||||
resolve("ok")
|
resolve("ok")
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Failed to upload new created public key!\nError: ${data.message}`)
|
throw new Error(`Failed to upload new created public key!\nError: ${data.message}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
492
src/home.ts
492
src/home.ts
@@ -1,246 +1,246 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import RemoteContainer from './remote-container';
|
import RemoteContainer from './remote-container';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
import * as utils from './utils'
|
import * as utils from './utils'
|
||||||
|
|
||||||
export default class DSHome {
|
export default class DSHome {
|
||||||
private context: vscode.ExtensionContext;
|
private context: vscode.ExtensionContext;
|
||||||
private remoteContainer: RemoteContainer;
|
private remoteContainer: RemoteContainer;
|
||||||
private user: User;
|
private user: User;
|
||||||
private devstarHomePageUrl: string;
|
private devstarHomePageUrl: string;
|
||||||
private devstarDomain: string | undefined
|
private devstarDomain: string | undefined
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext, user: User) {
|
constructor(context: vscode.ExtensionContext, user: User) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.remoteContainer = new RemoteContainer(user);
|
this.remoteContainer = new RemoteContainer(user);
|
||||||
|
|
||||||
this.devstarDomain = utils.devstarDomain()
|
this.devstarDomain = utils.devstarDomain()
|
||||||
if (undefined == this.devstarDomain || "" == this.devstarDomain) {
|
if (undefined == this.devstarDomain || "" == this.devstarDomain) {
|
||||||
this.devstarHomePageUrl = "https://devstar.cn/devstar-home"
|
this.devstarHomePageUrl = "https://devstar.cn/devstar-home"
|
||||||
} else {
|
} else {
|
||||||
this.devstarHomePageUrl = this.devstarDomain.endsWith('/') ? this.devstarDomain + "devstar-home" : this.devstarDomain + "/devstar-home"
|
this.devstarHomePageUrl = this.devstarDomain.endsWith('/') ? this.devstarDomain + "devstar-home" : this.devstarDomain + "/devstar-home"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggle(devstarHomePageUrl: string = this.devstarHomePageUrl) {
|
async toggle(devstarHomePageUrl: string = this.devstarHomePageUrl) {
|
||||||
const panel = vscode.window.createWebviewPanel(
|
const panel = vscode.window.createWebviewPanel(
|
||||||
'homeWebview',
|
'homeWebview',
|
||||||
vscode.l10n.t('Home'),
|
vscode.l10n.t('Home'),
|
||||||
vscode.ViewColumn.One,
|
vscode.ViewColumn.One,
|
||||||
{
|
{
|
||||||
enableScripts: true,
|
enableScripts: true,
|
||||||
retainContextWhenHidden: true,
|
retainContextWhenHidden: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
panel.webview.html = await this.getWebviewContent(devstarHomePageUrl);
|
panel.webview.html = await this.getWebviewContent(devstarHomePageUrl);
|
||||||
|
|
||||||
panel.webview.onDidReceiveMessage(
|
panel.webview.onDidReceiveMessage(
|
||||||
async (message) => {
|
async (message) => {
|
||||||
const data = message.data
|
const data = message.data
|
||||||
const need_return = message.need_return
|
const need_return = message.need_return
|
||||||
if (need_return) {
|
if (need_return) {
|
||||||
// ================= need return ====================
|
// ================= need return ====================
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
// ----------------- frequent -----------------------
|
// ----------------- frequent -----------------------
|
||||||
case 'getHomeConfig':
|
case 'getHomeConfig':
|
||||||
const config = {
|
const config = {
|
||||||
language: vscode.env.language
|
language: vscode.env.language
|
||||||
}
|
}
|
||||||
panel.webview.postMessage({command: 'getHomeConfig', data: {homeConfig: config}})
|
panel.webview.postMessage({command: 'getHomeConfig', data: {homeConfig: config}})
|
||||||
break;
|
break;
|
||||||
case 'getUserToken':
|
case 'getUserToken':
|
||||||
const userToken = this.user.getUserTokenFromLocal()
|
const userToken = this.user.getUserTokenFromLocal()
|
||||||
if (userToken === undefined) {
|
if (userToken === undefined) {
|
||||||
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: '' } })
|
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: '' } })
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: userToken } })
|
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: userToken } })
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'getUsername':
|
case 'getUsername':
|
||||||
const username = this.user.getUsernameFromLocal()
|
const username = this.user.getUsernameFromLocal()
|
||||||
if (username === undefined) {
|
if (username === undefined) {
|
||||||
panel.webview.postMessage({ command: 'getUsername', data: { username: '' } })
|
panel.webview.postMessage({ command: 'getUsername', data: { username: '' } })
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({ command: 'getUsername', data: { username: username } })
|
panel.webview.postMessage({ command: 'getUsername', data: { username: username } })
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'firstOpenRemoteFolder':
|
case 'firstOpenRemoteFolder':
|
||||||
// data.host - project name
|
// data.host - project name
|
||||||
await this.remoteContainer.firstOpenProject(data.host, data.hostname, data.port, data.username, data.path, this.context)
|
await this.remoteContainer.firstOpenProject(data.host, data.hostname, data.port, data.username, data.path, this.context)
|
||||||
break;
|
break;
|
||||||
case 'openRemoteFolder':
|
case 'openRemoteFolder':
|
||||||
this.remoteContainer.openRemoteFolder(data.host, data.port, data.username, data.path);
|
this.remoteContainer.openRemoteFolder(data.host, data.port, data.username, data.path);
|
||||||
break;
|
break;
|
||||||
case 'getDevstarDomain':
|
case 'getDevstarDomain':
|
||||||
panel.webview.postMessage({ command: 'getDevstarDomain', data: { devstarDomain: this.devstarDomain } })
|
panel.webview.postMessage({ command: 'getDevstarDomain', data: { devstarDomain: this.devstarDomain } })
|
||||||
break;
|
break;
|
||||||
// ----------------- not frequent -----------------------
|
// ----------------- not frequent -----------------------
|
||||||
case 'setUserToken':
|
case 'setUserToken':
|
||||||
this.user.setUserTokenToLocal(data.userToken)
|
this.user.setUserTokenToLocal(data.userToken)
|
||||||
if (data.userToken === this.user.getUserTokenFromLocal()) {
|
if (data.userToken === this.user.getUserTokenFromLocal()) {
|
||||||
panel.webview.postMessage({ command: 'setUserToken', data: { ok: true } })
|
panel.webview.postMessage({ command: 'setUserToken', data: { ok: true } })
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({ command: 'setUserToken', data: { ok: false } })
|
panel.webview.postMessage({ command: 'setUserToken', data: { ok: false } })
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'setUsername':
|
case 'setUsername':
|
||||||
this.user.setUsernameToLocal(data.username);
|
this.user.setUsernameToLocal(data.username);
|
||||||
if (data.username === this.user.getUsernameFromLocal()) {
|
if (data.username === this.user.getUsernameFromLocal()) {
|
||||||
panel.webview.postMessage({ command: 'setUsername', data: { ok: true } });
|
panel.webview.postMessage({ command: 'setUsername', data: { ok: true } });
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({ command: 'setUsername', data: { ok: false } });
|
panel.webview.postMessage({ command: 'setUsername', data: { ok: false } });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'getUserPublicKey':
|
case 'getUserPublicKey':
|
||||||
var userPublicKey = '';
|
var userPublicKey = '';
|
||||||
if (this.user.existUserPrivateKey()) {
|
if (this.user.existUserPrivateKey()) {
|
||||||
userPublicKey = this.user.getUserPublicKey();
|
userPublicKey = this.user.getUserPublicKey();
|
||||||
panel.webview.postMessage({ command: 'getUserPublicKey', data: { userPublicKey: userPublicKey } })
|
panel.webview.postMessage({ command: 'getUserPublicKey', data: { userPublicKey: userPublicKey } })
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({ command: 'getUserPublicKey', data: { userPublicKey: userPublicKey } })
|
panel.webview.postMessage({ command: 'getUserPublicKey', data: { userPublicKey: userPublicKey } })
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'createUserPublicKey':
|
case 'createUserPublicKey':
|
||||||
await this.user.createUserSSHKey();
|
await this.user.createUserSSHKey();
|
||||||
if (this.user.existUserPublicKey()) {
|
if (this.user.existUserPublicKey()) {
|
||||||
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: true } })
|
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: true } })
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: false } })
|
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: false } })
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'getMachineName':
|
case 'getMachineName':
|
||||||
const machineName = os.hostname();
|
const machineName = os.hostname();
|
||||||
panel.webview.postMessage({ command: 'getMachineName', data: { machineName: machineName } })
|
panel.webview.postMessage({ command: 'getMachineName', data: { machineName: machineName } })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ================= don't need return ==============
|
// ================= don't need return ==============
|
||||||
// frequent
|
// frequent
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
// ----------------- frequent -----------------------
|
// ----------------- frequent -----------------------
|
||||||
case 'showInformationNotification':
|
case 'showInformationNotification':
|
||||||
vscode.window.showInformationMessage(data.message);
|
vscode.window.showInformationMessage(data.message);
|
||||||
break;
|
break;
|
||||||
case 'showWarningNotification':
|
case 'showWarningNotification':
|
||||||
vscode.window.showWarningMessage(data.message)
|
vscode.window.showWarningMessage(data.message)
|
||||||
break;
|
break;
|
||||||
case 'showErrorNotification':
|
case 'showErrorNotification':
|
||||||
await utils.showErrorNotification(data.message)
|
await utils.showErrorNotification(data.message)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
this.context.subscriptions
|
this.context.subscriptions
|
||||||
);
|
);
|
||||||
|
|
||||||
this.context.subscriptions.push(panel)
|
this.context.subscriptions.push(panel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async getWebviewContent(devstarHomePageUrl: string): Promise<string> {
|
async getWebviewContent(devstarHomePageUrl: string): Promise<string> {
|
||||||
return `
|
return `
|
||||||
<?php
|
<?php
|
||||||
header("Access-Control-Allow-Origin: *");
|
header("Access-Control-Allow-Origin: *");
|
||||||
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method");
|
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method");
|
||||||
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
|
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
|
||||||
header("Allow: GET, POST, OPTIONS, PUT, DELETE");
|
header("Allow: GET, POST, OPTIONS, PUT, DELETE");
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>DevStar Home</title>
|
<title>DevStar Home</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<iframe id="embedded-devstar" src="${devstarHomePageUrl}" sandbox="allow-popups allow-same-origin allow-scripts allow-forms allow-top-navigation-by-user-activation" width="100%" height="100%" frameborder="0"
|
<iframe id="embedded-devstar" src="${devstarHomePageUrl}" sandbox="allow-popups allow-same-origin allow-scripts allow-forms allow-top-navigation-by-user-activation" width="100%" height="100%" frameborder="0"
|
||||||
style="border: 0; left: 0; right: 0; bottom: 0; top: 0; position:absolute;">
|
style="border: 0; left: 0; right: 0; bottom: 0; top: 0; position:absolute;">
|
||||||
</iframe>
|
</iframe>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const vscode = acquireVsCodeApi();
|
const vscode = acquireVsCodeApi();
|
||||||
|
|
||||||
function firstOpenRemoteFolder() {
|
function firstOpenRemoteFolder() {
|
||||||
vscode.postMessage({ command: 'firstOpenRemoteFolder', host: host, username: username, password: password, port: port, path: path });
|
vscode.postMessage({ command: 'firstOpenRemoteFolder', host: host, username: username, password: password, port: port, path: path });
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRemoteFolder() {
|
function openRemoteFolder() {
|
||||||
vscode.postMessage({ command: 'openRemoteFolder', host: host, path: path });
|
vscode.postMessage({ command: 'openRemoteFolder', host: host, path: path });
|
||||||
}
|
}
|
||||||
|
|
||||||
function firstOpenRemoteFolderWithData(host, username, password, port, path) {
|
function firstOpenRemoteFolderWithData(host, username, password, port, path) {
|
||||||
vscode.postMessage({ command: 'firstOpenRemoteFolder', host: host, username: username, password: password, port: port, path: path });
|
vscode.postMessage({ command: 'firstOpenRemoteFolder', host: host, username: username, password: password, port: port, path: path });
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRemoteFolderWithData(host, path) {
|
function openRemoteFolderWithData(host, path) {
|
||||||
vscode.postMessage({ command: 'openRemoteFolder', host: host, path: path });
|
vscode.postMessage({ command: 'openRemoteFolder', host: host, path: path });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function communicateVSCode(command, data) {
|
async function communicateVSCode(command, data) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// request to vscode
|
// request to vscode
|
||||||
vscode.postMessage({ command: command, need_return: true, data: data })
|
vscode.postMessage({ command: command, need_return: true, data: data })
|
||||||
|
|
||||||
function handleResponse(event) {
|
function handleResponse(event) {
|
||||||
const jsonData = event.data;
|
const jsonData = event.data;
|
||||||
if (jsonData.command === command) {
|
if (jsonData.command === command) {
|
||||||
// console.log("communicateVSCode", jsonData.data)
|
// console.log("communicateVSCode", jsonData.data)
|
||||||
|
|
||||||
// return vscode response
|
// return vscode response
|
||||||
window.removeEventListener('message', handleResponse) // 清理监听器
|
window.removeEventListener('message', handleResponse) // 清理监听器
|
||||||
resolve(jsonData.data)
|
resolve(jsonData.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('message', handleResponse)
|
window.addEventListener('message', handleResponse)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.removeEventListener('message', handleResponse)
|
window.removeEventListener('message', handleResponse)
|
||||||
reject('timeout')
|
reject('timeout')
|
||||||
}, 5000); // 5秒超时
|
}, 5000); // 5秒超时
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听子页面的消息
|
// 监听子页面的消息
|
||||||
window.addEventListener('message', async (event) => {
|
window.addEventListener('message', async (event) => {
|
||||||
// 出于安全考虑,检查 event.origin 是否是你预期的源
|
// 出于安全考虑,检查 event.origin 是否是你预期的源
|
||||||
// if (event.origin !== "http://expected-origin.com") {
|
// if (event.origin !== "http://expected-origin.com") {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
try {
|
try {
|
||||||
const jsonData = event.data;
|
const jsonData = event.data;
|
||||||
|
|
||||||
if (jsonData.target === 'vscode') {
|
if (jsonData.target === 'vscode') {
|
||||||
const actionFromHome = jsonData.action
|
const actionFromHome = jsonData.action
|
||||||
const dataFromHome = jsonData.data
|
const dataFromHome = jsonData.data
|
||||||
const dataFromVSCodeResponse = await communicateVSCode(actionFromHome, dataFromHome)
|
const dataFromVSCodeResponse = await communicateVSCode(actionFromHome, dataFromHome)
|
||||||
|
|
||||||
var iframe = document.getElementById('embedded-devstar');
|
var iframe = document.getElementById('embedded-devstar');
|
||||||
if (iframe && iframe.contentWindow) {
|
if (iframe && iframe.contentWindow) {
|
||||||
iframe.contentWindow.postMessage({ action: actionFromHome, data: dataFromVSCodeResponse }, '*')
|
iframe.contentWindow.postMessage({ action: actionFromHome, data: dataFromVSCodeResponse }, '*')
|
||||||
}
|
}
|
||||||
} else if (jsonData.target === 'vscode_no_return') {
|
} else if (jsonData.target === 'vscode_no_return') {
|
||||||
vscode.postMessage({ command: jsonData.action, need_return: false, data: jsonData.data })
|
vscode.postMessage({ command: jsonData.action, need_return: false, data: jsonData.data })
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing message:', error);
|
console.error('Error parsing message:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>`
|
</html>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
310
src/main.ts
310
src/main.ts
@@ -1,155 +1,155 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import QuickAccessTreeProvider from './views/quick-access-tree';
|
import QuickAccessTreeProvider from './views/quick-access-tree';
|
||||||
import DSHome from './home';
|
import DSHome from './home';
|
||||||
import RemoteContainer, { openProjectWithoutLogging } from './remote-container';
|
import RemoteContainer, { openProjectWithoutLogging } from './remote-container';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
import DevstarAPIHandler from './devstar-api';
|
import DevstarAPIHandler from './devstar-api';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
|
|
||||||
export class DevStarExtension {
|
export class DevStarExtension {
|
||||||
user: User;
|
user: User;
|
||||||
remoteContainer: RemoteContainer;
|
remoteContainer: RemoteContainer;
|
||||||
dsHome: DSHome;
|
dsHome: DSHome;
|
||||||
|
|
||||||
constructor(private context: vscode.ExtensionContext) {
|
constructor(private context: vscode.ExtensionContext) {
|
||||||
this.user = new User(context);
|
this.user = new User(context);
|
||||||
// 只保持一个User实例
|
// 只保持一个User实例
|
||||||
this.remoteContainer = new RemoteContainer(this.user);
|
this.remoteContainer = new RemoteContainer(this.user);
|
||||||
this.dsHome = new DSHome(context, this.user);
|
this.dsHome = new DSHome(context, this.user);
|
||||||
|
|
||||||
// 确定local系统是否为win,如果是,保存powershell版本
|
// 确定local系统是否为win,如果是,保存powershell版本
|
||||||
if (vscode.env.remoteName === undefined) {
|
if (vscode.env.remoteName === undefined) {
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
utils.powershellVersion()
|
utils.powershellVersion()
|
||||||
.then(powershellVersion => {
|
.then(powershellVersion => {
|
||||||
this.context.globalState.update('powershellVersion', powershellVersion)
|
this.context.globalState.update('powershellVersion', powershellVersion)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// support for open with vscode in web
|
// support for open with vscode in web
|
||||||
const handler = vscode.window.registerUriHandler({
|
const handler = vscode.window.registerUriHandler({
|
||||||
handleUri: async (uri: vscode.Uri) => {
|
handleUri: async (uri: vscode.Uri) => {
|
||||||
const devstarAPIHandler = new DevstarAPIHandler()
|
const devstarAPIHandler = new DevstarAPIHandler()
|
||||||
|
|
||||||
if (uri.path === '/openProject') {
|
if (uri.path === '/openProject') {
|
||||||
const params = new URLSearchParams(uri.query);
|
const params = new URLSearchParams(uri.query);
|
||||||
const host = params.get('host');
|
const host = params.get('host');
|
||||||
const hostname = params.get('hostname');
|
const hostname = params.get('hostname');
|
||||||
const port = params.get('port');
|
const port = params.get('port');
|
||||||
const username = params.get('username');
|
const username = params.get('username');
|
||||||
const path = params.get('path');
|
const path = params.get('path');
|
||||||
const access_token = params.get('access_token');
|
const access_token = params.get('access_token');
|
||||||
const devstar_username = params.get('devstar_username');
|
const devstar_username = params.get('devstar_username');
|
||||||
|
|
||||||
if (host && hostname && port && username && path) {
|
if (host && hostname && port && username && path) {
|
||||||
const container_host = host;
|
const container_host = host;
|
||||||
const container_hostname = hostname
|
const container_hostname = hostname
|
||||||
const container_port = parseInt(port, 10);
|
const container_port = parseInt(port, 10);
|
||||||
const container_username = username;
|
const container_username = username;
|
||||||
const project_path = decodeURIComponent(path);
|
const project_path = decodeURIComponent(path);
|
||||||
|
|
||||||
if (access_token && devstar_username) {
|
if (access_token && devstar_username) {
|
||||||
if (!this.user.isLogged()) {
|
if (!this.user.isLogged()) {
|
||||||
// 如果没有用户登录,则直接登录;
|
// 如果没有用户登录,则直接登录;
|
||||||
const res = await this.user.login(access_token, devstar_username)
|
const res = await this.user.login(access_token, devstar_username)
|
||||||
if (res === 'ok') {
|
if (res === 'ok') {
|
||||||
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
||||||
}
|
}
|
||||||
} else if (devstar_username === this.user.getUsernameFromLocal()) {
|
} else if (devstar_username === this.user.getUsernameFromLocal()) {
|
||||||
// 如果同用户已经登录,则忽略,直接打开项目
|
// 如果同用户已经登录,则忽略,直接打开项目
|
||||||
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
||||||
} else {
|
} else {
|
||||||
// 如果不是同用户,可以选择切换用户,或者不切换登录用户,直接打开容器
|
// 如果不是同用户,可以选择切换用户,或者不切换登录用户,直接打开容器
|
||||||
const selection = await vscode.window.showWarningMessage(`已登录用户:${this.user.getUsernameFromLocal()},是否切换用户?`,
|
const selection = await vscode.window.showWarningMessage(`已登录用户:${this.user.getUsernameFromLocal()},是否切换用户?`,
|
||||||
'Yes', 'No',);
|
'Yes', 'No',);
|
||||||
if (selection === 'Yes') {
|
if (selection === 'Yes') {
|
||||||
// 如果没有用户登录,则直接登录;
|
// 如果没有用户登录,则直接登录;
|
||||||
const res = await this.user.login(access_token, devstar_username)
|
const res = await this.user.login(access_token, devstar_username)
|
||||||
if (res === 'ok') {
|
if (res === 'ok') {
|
||||||
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
||||||
}
|
}
|
||||||
} else if (selection === 'No') {
|
} else if (selection === 'No') {
|
||||||
await openProjectWithoutLogging(container_host, container_port, container_username, project_path);
|
await openProjectWithoutLogging(container_host, container_port, container_username, project_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await openProjectWithoutLogging(container_host, container_port, container_username, project_path);
|
await openProjectWithoutLogging(container_host, container_port, container_username, project_path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vscode.window.showErrorMessage('Missing required parameters.');
|
vscode.window.showErrorMessage('Missing required parameters.');
|
||||||
}
|
}
|
||||||
} else if (uri.path === "/openProjectSkippingLoginCheck") {
|
} else if (uri.path === "/openProjectSkippingLoginCheck") {
|
||||||
// 仅有已登录、不用改变登录状态时,用此流程
|
// 仅有已登录、不用改变登录状态时,用此流程
|
||||||
const params = new URLSearchParams(uri.query);
|
const params = new URLSearchParams(uri.query);
|
||||||
const host = params.get('host');
|
const host = params.get('host');
|
||||||
const hostname = params.get('hostname');
|
const hostname = params.get('hostname');
|
||||||
const port = params.get('port');
|
const port = params.get('port');
|
||||||
const username = params.get('username');
|
const username = params.get('username');
|
||||||
const path = params.get('path');
|
const path = params.get('path');
|
||||||
|
|
||||||
if (host && hostname && port && username && path) {
|
if (host && hostname && port && username && path) {
|
||||||
const container_host = host;
|
const container_host = host;
|
||||||
const container_hostname = hostname
|
const container_hostname = hostname
|
||||||
const container_port = parseInt(port, 10);
|
const container_port = parseInt(port, 10);
|
||||||
const container_username = username;
|
const container_username = username;
|
||||||
const project_path = decodeURIComponent(path);
|
const project_path = decodeURIComponent(path);
|
||||||
|
|
||||||
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
context.subscriptions.push(handler);
|
context.subscriptions.push(handler);
|
||||||
|
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
vscode.window.registerTreeDataProvider(
|
vscode.window.registerTreeDataProvider(
|
||||||
'devstar.quickAccess',
|
'devstar.quickAccess',
|
||||||
new QuickAccessTreeProvider()
|
new QuickAccessTreeProvider()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.registerGlobalCommands(context);
|
this.registerGlobalCommands(context);
|
||||||
|
|
||||||
this.startDevStarHome();
|
this.startDevStarHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async startDevStarHome() {
|
async startDevStarHome() {
|
||||||
vscode.commands.executeCommand('devstar.showHome');
|
vscode.commands.executeCommand('devstar.showHome');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
registerGlobalCommands(context: vscode.ExtensionContext) {
|
registerGlobalCommands(context: vscode.ExtensionContext) {
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
vscode.commands.registerCommand('devstar.showHome', (url: string) =>
|
vscode.commands.registerCommand('devstar.showHome', (url: string) =>
|
||||||
this.dsHome.toggle(url)
|
this.dsHome.toggle(url)
|
||||||
),
|
),
|
||||||
vscode.commands.registerCommand('devstar.clean', () => {
|
vscode.commands.registerCommand('devstar.clean', () => {
|
||||||
// 先清除ssh key
|
// 先清除ssh key
|
||||||
if (fs.existsSync(this.user.getUserPrivateKeyPath())) {
|
if (fs.existsSync(this.user.getUserPrivateKeyPath())) {
|
||||||
fs.unlinkSync(this.user.getUserPrivateKeyPath())
|
fs.unlinkSync(this.user.getUserPrivateKeyPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs.existsSync(this.user.getUserPublicKeyPath())) {
|
if (fs.existsSync(this.user.getUserPublicKeyPath())) {
|
||||||
fs.unlinkSync(this.user.getUserPublicKeyPath())
|
fs.unlinkSync(this.user.getUserPublicKeyPath())
|
||||||
}
|
}
|
||||||
console.log("User's ssh key has been deleted!")
|
console.log("User's ssh key has been deleted!")
|
||||||
// 更新local user private key path
|
// 更新local user private key path
|
||||||
this.user.updateLocalUserPrivateKeyPath("")
|
this.user.updateLocalUserPrivateKeyPath("")
|
||||||
// 退出登录
|
// 退出登录
|
||||||
this.user.logout()
|
this.user.logout()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
return new DevStarExtension(context);
|
return new DevStarExtension(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {
|
export function deactivate() {
|
||||||
}
|
}
|
||||||
|
@@ -1,204 +1,204 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as rd from 'readline'
|
import * as rd from 'readline'
|
||||||
const { NodeSSH } = require('node-ssh')
|
const { NodeSSH } = require('node-ssh')
|
||||||
|
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
import DevstarAPIHandler from './devstar-api';
|
import DevstarAPIHandler from './devstar-api';
|
||||||
|
|
||||||
export default class RemoteContainer {
|
export default class RemoteContainer {
|
||||||
private user: User;
|
private user: User;
|
||||||
|
|
||||||
constructor(user: User) {
|
constructor(user: User) {
|
||||||
this.user = user
|
this.user = user
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第一次打开远程项目
|
* 第一次打开远程项目
|
||||||
*
|
*
|
||||||
* 远程环境,先创建local窗口,在通过命令行调用url打开(目前,仅支持vscode协议)
|
* 远程环境,先创建local窗口,在通过命令行调用url打开(目前,仅支持vscode协议)
|
||||||
* @param host 项目名称
|
* @param host 项目名称
|
||||||
* @param hostname ip
|
* @param hostname ip
|
||||||
* @param port
|
* @param port
|
||||||
* @param username
|
* @param username
|
||||||
* @param path
|
* @param path
|
||||||
* @param context 用于支持远程项目环境
|
* @param context 用于支持远程项目环境
|
||||||
*/
|
*/
|
||||||
async firstOpenProject(host: string, hostname: string, port: number, username: string, path: string, context: vscode.ExtensionContext) {
|
async firstOpenProject(host: string, hostname: string, port: number, username: string, path: string, context: vscode.ExtensionContext) {
|
||||||
if (vscode.env.remoteName) {
|
if (vscode.env.remoteName) {
|
||||||
// 远程环境
|
// 远程环境
|
||||||
vscode.commands.executeCommand('workbench.action.terminal.newLocal').then(() => {
|
vscode.commands.executeCommand('workbench.action.terminal.newLocal').then(() => {
|
||||||
const terminal = vscode.window.terminals[vscode.window.terminals.length - 1];
|
const terminal = vscode.window.terminals[vscode.window.terminals.length - 1];
|
||||||
if (terminal) {
|
if (terminal) {
|
||||||
// vscode协议
|
// vscode协议
|
||||||
// 根据系统+命令行版本确定命令
|
// 根据系统+命令行版本确定命令
|
||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
const powershellVersion = context.globalState.get('powershellVersion')
|
const powershellVersion = context.globalState.get('powershellVersion')
|
||||||
const powershell_semver_compatible_version = semver.coerce(powershellVersion)
|
const powershell_semver_compatible_version = semver.coerce(powershellVersion)
|
||||||
if (powershellVersion === undefined)
|
if (powershellVersion === undefined)
|
||||||
terminal.sendText(`code --new-window && code --open-url "vscode://mengning.devstar/openProjectSkippingLoginCheck?host=${host}&hostname=${hostname}&port=${port}&username=${username}&path=${path}"`)
|
terminal.sendText(`code --new-window && code --open-url "vscode://mengning.devstar/openProjectSkippingLoginCheck?host=${host}&hostname=${hostname}&port=${port}&username=${username}&path=${path}"`)
|
||||||
else if (semver.satisfies(powershell_semver_compatible_version, ">=5.1.26100")) {
|
else if (semver.satisfies(powershell_semver_compatible_version, ">=5.1.26100")) {
|
||||||
// win & powershell >= 5.1.26100.0
|
// win & powershell >= 5.1.26100.0
|
||||||
terminal.sendText(`code --new-window ; code --% --open-url "vscode://mengning.devstar/openProjectSkippingLoginCheck?host=${host}&hostname=${hostname}&port=${port}&username=${username}&path=${path}"`)
|
terminal.sendText(`code --new-window ; code --% --open-url "vscode://mengning.devstar/openProjectSkippingLoginCheck?host=${host}&hostname=${hostname}&port=${port}&username=${username}&path=${path}"`)
|
||||||
} else {
|
} else {
|
||||||
// win & powershell < 5.1.26100.0
|
// win & powershell < 5.1.26100.0
|
||||||
terminal.sendText(`code --new-window && code --open-url "vscode://mengning.devstar/openProjectSkippingLoginCheck?host=${host}&hostname=${hostname}&port=${port}&username=${username}&path=${path}"`)
|
terminal.sendText(`code --new-window && code --open-url "vscode://mengning.devstar/openProjectSkippingLoginCheck?host=${host}&hostname=${hostname}&port=${port}&username=${username}&path=${path}"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
await this.firstConnect(host, hostname, username, port)
|
await this.firstConnect(host, hostname, username, port)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res === 'success') {
|
if (res === 'success') {
|
||||||
// only success then open folder
|
// only success then open folder
|
||||||
this.openRemoteFolder(host, port, username, path);
|
this.openRemoteFolder(host, port, username, path);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* local environment,第一次连接其他项目
|
* local environment,第一次连接其他项目
|
||||||
* @param host 项目名称
|
* @param host 项目名称
|
||||||
* @param hostname ip
|
* @param hostname ip
|
||||||
* @param username
|
* @param username
|
||||||
* @param port
|
* @param port
|
||||||
* @returns 成功返回success
|
* @returns 成功返回success
|
||||||
*/
|
*/
|
||||||
// connect with key
|
// connect with key
|
||||||
async firstConnect(host: string, hostname: string, username: string, port: number): Promise<string> {
|
async firstConnect(host: string, hostname: string, username: string, port: number): Promise<string> {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const ssh = new NodeSSH();
|
const ssh = new NodeSSH();
|
||||||
vscode.window.withProgress({
|
vscode.window.withProgress({
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
title: vscode.l10n.t("Installing vscode-server and devstar extension in container"),
|
title: vscode.l10n.t("Installing vscode-server and devstar extension in container"),
|
||||||
cancellable: false
|
cancellable: false
|
||||||
}, async (progress) => {
|
}, async (progress) => {
|
||||||
try {
|
try {
|
||||||
// 检查公私钥是否存在,如果不存在,需要创建
|
// 检查公私钥是否存在,如果不存在,需要创建
|
||||||
if (!this.user.existUserPrivateKey() || !this.user.existUserPublicKey()) {
|
if (!this.user.existUserPrivateKey() || !this.user.existUserPublicKey()) {
|
||||||
await this.user.createUserSSHKey()
|
await this.user.createUserSSHKey()
|
||||||
// 上传公钥
|
// 上传公钥
|
||||||
const devstarAPIHandler = new DevstarAPIHandler()
|
const devstarAPIHandler = new DevstarAPIHandler()
|
||||||
const uploadResult = await devstarAPIHandler.uploadUserPublicKey(this.user)
|
const uploadResult = await devstarAPIHandler.uploadUserPublicKey(this.user)
|
||||||
if (uploadResult !== "ok") {
|
if (uploadResult !== "ok") {
|
||||||
throw new Error('Upload public key failed.')
|
throw new Error('Upload public key failed.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to first connect container: ", error)
|
console.error("Failed to first connect container: ", error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本地环境
|
// 本地环境
|
||||||
try {
|
try {
|
||||||
// connect with key
|
// connect with key
|
||||||
await ssh.connect({
|
await ssh.connect({
|
||||||
host: hostname,
|
host: hostname,
|
||||||
username: username,
|
username: username,
|
||||||
port: port,
|
port: port,
|
||||||
privateKeyPath: this.user.getUserPrivateKeyPath()
|
privateKeyPath: this.user.getUserPrivateKeyPath()
|
||||||
});
|
});
|
||||||
progress.report({ message: vscode.l10n.t("Connected! Start installation") });
|
progress.report({ message: vscode.l10n.t("Connected! Start installation") });
|
||||||
|
|
||||||
// install vscode-server and devstar extension
|
// install vscode-server and devstar extension
|
||||||
const vscodeCommitId = await utils.getVsCodeCommitId()
|
const vscodeCommitId = await utils.getVsCodeCommitId()
|
||||||
if ("" != vscodeCommitId) {
|
if ("" != vscodeCommitId) {
|
||||||
const vscodeServerUrl = `https://vscode.download.prss.microsoft.com/dbazure/download/stable/${vscodeCommitId}/vscode-server-linux-x64.tar.gz`
|
const vscodeServerUrl = `https://vscode.download.prss.microsoft.com/dbazure/download/stable/${vscodeCommitId}/vscode-server-linux-x64.tar.gz`
|
||||||
const installVscodeServerScript = `
|
const installVscodeServerScript = `
|
||||||
mkdir -p ~/.vscode-server/bin/${vscodeCommitId} && \\
|
mkdir -p ~/.vscode-server/bin/${vscodeCommitId} && \\
|
||||||
if [ "$(ls -A ~/.vscode-server/bin/${vscodeCommitId})" ]; then
|
if [ "$(ls -A ~/.vscode-server/bin/${vscodeCommitId})" ]; then
|
||||||
~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar
|
~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar
|
||||||
else
|
else
|
||||||
wget ${vscodeServerUrl} -O vscode-server-linux-x64.tar.gz && \\
|
wget ${vscodeServerUrl} -O vscode-server-linux-x64.tar.gz && \\
|
||||||
mv vscode-server-linux-x64.tar.gz ~/.vscode-server/bin/${vscodeCommitId} && \\
|
mv vscode-server-linux-x64.tar.gz ~/.vscode-server/bin/${vscodeCommitId} && \\
|
||||||
cd ~/.vscode-server/bin/${vscodeCommitId} && \\
|
cd ~/.vscode-server/bin/${vscodeCommitId} && \\
|
||||||
tar -xvzf vscode-server-linux-x64.tar.gz --strip-components 1 && \\
|
tar -xvzf vscode-server-linux-x64.tar.gz --strip-components 1 && \\
|
||||||
rm vscode-server-linux-x64.tar.gz && \\
|
rm vscode-server-linux-x64.tar.gz && \\
|
||||||
~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar
|
~/.vscode-server/bin/${vscodeCommitId}/bin/code-server --install-extension mengning.devstar
|
||||||
fi
|
fi
|
||||||
`;
|
`;
|
||||||
await ssh.execCommand(installVscodeServerScript);
|
await ssh.execCommand(installVscodeServerScript);
|
||||||
console.log("vscode-server and extension installed");
|
console.log("vscode-server and extension installed");
|
||||||
vscode.window.showInformationMessage(vscode.l10n.t('Installation completed!'));
|
vscode.window.showInformationMessage(vscode.l10n.t('Installation completed!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
await ssh.dispose();
|
await ssh.dispose();
|
||||||
|
|
||||||
// only connect successfully then save the host info
|
// only connect successfully then save the host info
|
||||||
await this.storeProjectSSHInfo(host, hostname, port, username)
|
await this.storeProjectSSHInfo(host, hostname, port, username)
|
||||||
|
|
||||||
resolve('success')
|
resolve('success')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to install vscode-server and extension: ', error);
|
console.error('Failed to install vscode-server and extension: ', error);
|
||||||
await ssh.dispose();
|
await ssh.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地环境,保存项目的ssh连接信息
|
* 本地环境,保存项目的ssh连接信息
|
||||||
* @param host
|
* @param host
|
||||||
* @param hostname
|
* @param hostname
|
||||||
* @param port
|
* @param port
|
||||||
* @param username
|
* @param username
|
||||||
*/
|
*/
|
||||||
async storeProjectSSHInfo(host: string, hostname: string, port: number, username: string): Promise<void> {
|
async storeProjectSSHInfo(host: string, hostname: string, port: number, username: string): Promise<void> {
|
||||||
const sshConfigPath = path.join(os.homedir(), '.ssh', 'config');
|
const sshConfigPath = path.join(os.homedir(), '.ssh', 'config');
|
||||||
// check if the host and related info exist in local ssh config file before saving
|
// check if the host and related info exist in local ssh config file before saving
|
||||||
var canAppendSSHConfig = true
|
var canAppendSSHConfig = true
|
||||||
if (fs.existsSync(sshConfigPath)) {
|
if (fs.existsSync(sshConfigPath)) {
|
||||||
var reader = rd.createInterface(fs.createReadStream(sshConfigPath))
|
var reader = rd.createInterface(fs.createReadStream(sshConfigPath))
|
||||||
|
|
||||||
for await (const line of reader) {
|
for await (const line of reader) {
|
||||||
if (line.includes(`Host ${host}`)) {
|
if (line.includes(`Host ${host}`)) {
|
||||||
// the container ssh info exists
|
// the container ssh info exists
|
||||||
canAppendSSHConfig = false
|
canAppendSSHConfig = false
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAppendSSHConfig) {
|
if (canAppendSSHConfig) {
|
||||||
// save the host to the local ssh config file
|
// save the host to the local ssh config file
|
||||||
const privateKeyPath = this.user.getUserPrivateKeyPath();
|
const privateKeyPath = this.user.getUserPrivateKeyPath();
|
||||||
const newSShConfigContent =
|
const newSShConfigContent =
|
||||||
`\nHost ${host}\n HostName ${hostname}\n Port ${port}\n User ${username}\n PreferredAuthentications publickey\n IdentityFile ${privateKeyPath}\n `;
|
`\nHost ${host}\n HostName ${hostname}\n Port ${port}\n User ${username}\n PreferredAuthentications publickey\n IdentityFile ${privateKeyPath}\n `;
|
||||||
fs.writeFileSync(sshConfigPath, newSShConfigContent, { encoding: 'utf8', flag: 'a' });
|
fs.writeFileSync(sshConfigPath, newSShConfigContent, { encoding: 'utf8', flag: 'a' });
|
||||||
console.log('Host registered in local ssh config');
|
console.log('Host registered in local ssh config');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* local env
|
* local env
|
||||||
* 仅支持已经成功连接,并在ssh config file中存储ssh信息的项目连接。
|
* 仅支持已经成功连接,并在ssh config file中存储ssh信息的项目连接。
|
||||||
*
|
*
|
||||||
* @host 表示project name
|
* @host 表示project name
|
||||||
*/
|
*/
|
||||||
openRemoteFolder(host: string, port: number, username: string, path: string): void {
|
openRemoteFolder(host: string, port: number, username: string, path: string): void {
|
||||||
let terminal = vscode.window.activeTerminal || vscode.window.createTerminal(`Ext Terminal`);
|
let terminal = vscode.window.activeTerminal || vscode.window.createTerminal(`Ext Terminal`);
|
||||||
terminal.show(true);
|
terminal.show(true);
|
||||||
// 在原窗口打开
|
// 在原窗口打开
|
||||||
terminal.sendText(`code --remote ssh-remote+${username}@${host}:${port} ${path} --reuse-window`);
|
terminal.sendText(`code --remote ssh-remote+${username}@${host}:${port} ${path} --reuse-window`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开项目(无须插件登录)
|
* 打开项目(无须插件登录)
|
||||||
* @param hostname 表示ip
|
* @param hostname 表示ip
|
||||||
* @param port
|
* @param port
|
||||||
* @param username
|
* @param username
|
||||||
* @param path
|
* @param path
|
||||||
*/
|
*/
|
||||||
export async function openProjectWithoutLogging(hostname: string, port: number, username: string, path: string): Promise<void> {
|
export async function openProjectWithoutLogging(hostname: string, port: number, username: string, path: string): Promise<void> {
|
||||||
const command = `code --remote ssh-remote+${username}@${hostname}:${port} ${path} --reuse-window`
|
const command = `code --remote ssh-remote+${username}@${hostname}:${port} ${path} --reuse-window`
|
||||||
let terminal = vscode.window.activeTerminal || vscode.window.createTerminal(`Ext Terminal`);
|
let terminal = vscode.window.activeTerminal || vscode.window.createTerminal(`Ext Terminal`);
|
||||||
terminal.show(true);
|
terminal.show(true);
|
||||||
terminal.sendText(command);
|
terminal.sendText(command);
|
||||||
}
|
}
|
426
src/user.ts
426
src/user.ts
@@ -1,214 +1,214 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import DevstarAPIHandler from './devstar-api';
|
import DevstarAPIHandler from './devstar-api';
|
||||||
import { showErrorNotification } from './utils';
|
import { showErrorNotification } from './utils';
|
||||||
const {
|
const {
|
||||||
generateKeyPairSync,
|
generateKeyPairSync,
|
||||||
createHash
|
createHash
|
||||||
} = require('node:crypto');
|
} = require('node:crypto');
|
||||||
const sshpk = require('sshpk');
|
const sshpk = require('sshpk');
|
||||||
|
|
||||||
export default class User {
|
export default class User {
|
||||||
private context: vscode.ExtensionContext;
|
private context: vscode.ExtensionContext;
|
||||||
private username: string | undefined;
|
private username: string | undefined;
|
||||||
private userToken: string | undefined;
|
private userToken: string | undefined;
|
||||||
private usernameKey: string = 'devstarUsername'
|
private usernameKey: string = 'devstarUsername'
|
||||||
private userTokenKey: string = 'devstarUserToken'
|
private userTokenKey: string = 'devstarUserToken'
|
||||||
private localUserPrivateKeyPath: string = ''
|
private localUserPrivateKeyPath: string = ''
|
||||||
private devstarHostname: string;
|
private devstarHostname: string;
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext) {
|
constructor(context: vscode.ExtensionContext) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.username = this.context.globalState.get(this.usernameKey);
|
this.username = this.context.globalState.get(this.usernameKey);
|
||||||
this.userToken = this.context.globalState.get(this.userTokenKey);
|
this.userToken = this.context.globalState.get(this.userTokenKey);
|
||||||
|
|
||||||
// 提取devstar domain的主域名,用于本地ssh key的命名
|
// 提取devstar domain的主域名,用于本地ssh key的命名
|
||||||
let devstarDomainFromConfig: string | undefined;
|
let devstarDomainFromConfig: string | undefined;
|
||||||
let devstarDomainURL: string;
|
let devstarDomainURL: string;
|
||||||
devstarDomainFromConfig = vscode.workspace.getConfiguration('devstar').get('devstarDomain')
|
devstarDomainFromConfig = vscode.workspace.getConfiguration('devstar').get('devstarDomain')
|
||||||
// 如果没有配置devstar domain,则默认domain为https://devstar.cn
|
// 如果没有配置devstar domain,则默认domain为https://devstar.cn
|
||||||
devstarDomainURL = (devstarDomainFromConfig === undefined || devstarDomainFromConfig === "") ? 'https://devstar.cn' : devstarDomainFromConfig;
|
devstarDomainURL = (devstarDomainFromConfig === undefined || devstarDomainFromConfig === "") ? 'https://devstar.cn' : devstarDomainFromConfig;
|
||||||
let parsedUrl = new URL(devstarDomainURL);
|
let parsedUrl = new URL(devstarDomainURL);
|
||||||
this.devstarHostname = parsedUrl.hostname.replace(/\./g, '_'); //提取hostname,并用下划线替换.
|
this.devstarHostname = parsedUrl.hostname.replace(/\./g, '_'); //提取hostname,并用下划线替换.
|
||||||
}
|
}
|
||||||
|
|
||||||
public async login(token: string, username: string) {
|
public async login(token: string, username: string) {
|
||||||
const devstarAPIHandler = new DevstarAPIHandler()
|
const devstarAPIHandler = new DevstarAPIHandler()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await devstarAPIHandler.verifyToken(token, username)
|
const res = await devstarAPIHandler.verifyToken(token, username)
|
||||||
if (!res) {
|
if (!res) {
|
||||||
throw new Error('Token verification failed')
|
throw new Error('Token verification failed')
|
||||||
}
|
}
|
||||||
|
|
||||||
// token与用户名验证通过
|
// token与用户名验证通过
|
||||||
// 插件登录:存储token与用户名
|
// 插件登录:存储token与用户名
|
||||||
this.setUserTokenToLocal(token)
|
this.setUserTokenToLocal(token)
|
||||||
this.setUsernameToLocal(username)
|
this.setUsernameToLocal(username)
|
||||||
|
|
||||||
// 检查本地是否有用户所属公钥,没有则创建
|
// 检查本地是否有用户所属公钥,没有则创建
|
||||||
if (!this.existUserPublicKey()) {
|
if (!this.existUserPublicKey()) {
|
||||||
await this.createUserSSHKey()
|
await this.createUserSSHKey()
|
||||||
|
|
||||||
// 上传公钥
|
// 上传公钥
|
||||||
const uploadResult = await devstarAPIHandler.uploadUserPublicKey(this)
|
const uploadResult = await devstarAPIHandler.uploadUserPublicKey(this)
|
||||||
if (uploadResult !== 'ok') {
|
if (uploadResult !== 'ok') {
|
||||||
throw new Error('Upload user public key failed')
|
throw new Error('Upload user public key failed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vscode.window.showInformationMessage(vscode.l10n.t('User login successfully!'))
|
vscode.window.showInformationMessage(vscode.l10n.t('User login successfully!'))
|
||||||
return 'ok'
|
return 'ok'
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
await showErrorNotification('用户登录失败!')
|
await showErrorNotification('用户登录失败!')
|
||||||
return 'login failed'
|
return 'login failed'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public logout() {
|
public logout() {
|
||||||
this.setUserTokenToLocal("")
|
this.setUserTokenToLocal("")
|
||||||
this.setUsernameToLocal("")
|
this.setUsernameToLocal("")
|
||||||
vscode.window.showInformationMessage(vscode.l10n.t("User has logged out!"))
|
vscode.window.showInformationMessage(vscode.l10n.t("User has logged out!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
public isLogged() {
|
public isLogged() {
|
||||||
var existUsername = false;
|
var existUsername = false;
|
||||||
var existUserToken = false;
|
var existUserToken = false;
|
||||||
if (this.username != undefined && this.username != '') {
|
if (this.username != undefined && this.username != '') {
|
||||||
existUsername = true;
|
existUsername = true;
|
||||||
}
|
}
|
||||||
if (this.userToken != undefined && this.userToken != '') {
|
if (this.userToken != undefined && this.userToken != '') {
|
||||||
existUserToken = true;
|
existUserToken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existUsername && existUserToken) {
|
if (existUsername && existUserToken) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUsernameFromLocal(): string | undefined {
|
public getUsernameFromLocal(): string | undefined {
|
||||||
return this.username;
|
return this.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserTokenFromLocal(): string | undefined {
|
public getUserTokenFromLocal(): string | undefined {
|
||||||
return this.userToken;
|
return this.userToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setUsernameToLocal(username: string) {
|
public setUsernameToLocal(username: string) {
|
||||||
this.context.globalState.update(this.usernameKey, username);
|
this.context.globalState.update(this.usernameKey, username);
|
||||||
this.username = username;
|
this.username = username;
|
||||||
if (username !== "") {
|
if (username !== "") {
|
||||||
console.log('Username has been stored.')
|
console.log('Username has been stored.')
|
||||||
} else {
|
} else {
|
||||||
console.log('Username has been cleaned up.')
|
console.log('Username has been cleaned up.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setUserTokenToLocal(userToken: string) {
|
public setUserTokenToLocal(userToken: string) {
|
||||||
this.context.globalState.update(this.userTokenKey, userToken)
|
this.context.globalState.update(this.userTokenKey, userToken)
|
||||||
this.userToken = userToken
|
this.userToken = userToken
|
||||||
if (userToken !== "") {
|
if (userToken !== "") {
|
||||||
console.log('Token has been stored.');
|
console.log('Token has been stored.');
|
||||||
} else {
|
} else {
|
||||||
console.log('Token has been cleaned up.')
|
console.log('Token has been cleaned up.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateLocalUserPrivateKeyPath(localUserPrivateKeyPath: string) {
|
public updateLocalUserPrivateKeyPath(localUserPrivateKeyPath: string) {
|
||||||
this.context.globalState.update('localUserPrivateKeyPath', localUserPrivateKeyPath)
|
this.context.globalState.update('localUserPrivateKeyPath', localUserPrivateKeyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getLocalUserPrivateKeyPath(): undefined | string {
|
public getLocalUserPrivateKeyPath(): undefined | string {
|
||||||
return this.context.globalState.get('localUserPrivateKeyPath')
|
return this.context.globalState.get('localUserPrivateKeyPath')
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserPrivateKeyPath(): string {
|
public getUserPrivateKeyPath(): string {
|
||||||
if (!this.isLogged) {
|
if (!this.isLogged) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}`)
|
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserPublicKeyPath(): string {
|
public getUserPublicKeyPath(): string {
|
||||||
if (!this.isLogged) {
|
if (!this.isLogged) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}.pub`)
|
return path.join(os.homedir(), '.ssh', `id_rsa_${this.username}_${this.devstarHostname}.pub`)
|
||||||
}
|
}
|
||||||
|
|
||||||
public existUserPublicKey(): boolean {
|
public existUserPublicKey(): boolean {
|
||||||
const userPublicKeyPath = this.getUserPublicKeyPath();
|
const userPublicKeyPath = this.getUserPublicKeyPath();
|
||||||
return fs.existsSync(userPublicKeyPath)
|
return fs.existsSync(userPublicKeyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
public existUserPrivateKey(): boolean {
|
public existUserPrivateKey(): boolean {
|
||||||
const userPrivateKeyPath = this.getUserPrivateKeyPath();
|
const userPrivateKeyPath = this.getUserPrivateKeyPath();
|
||||||
return fs.existsSync(userPrivateKeyPath)
|
return fs.existsSync(userPrivateKeyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserPublicKey(): string {
|
public getUserPublicKey(): string {
|
||||||
const userPublicKeyPath = this.getUserPublicKeyPath();
|
const userPublicKeyPath = this.getUserPublicKeyPath();
|
||||||
const userPublicKey = fs.readFileSync(userPublicKeyPath, 'utf-8');
|
const userPublicKey = fs.readFileSync(userPublicKeyPath, 'utf-8');
|
||||||
// remove `\r` `\n`
|
// remove `\r` `\n`
|
||||||
const trimmedDefaultPublicKey = userPublicKey.replace(/[\r\n]/g, "");
|
const trimmedDefaultPublicKey = userPublicKey.replace(/[\r\n]/g, "");
|
||||||
return trimmedDefaultPublicKey;
|
return trimmedDefaultPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserPrivateKey(): string {
|
public getUserPrivateKey(): string {
|
||||||
const userPrivateKey = this.getUserPrivateKeyPath();
|
const userPrivateKey = this.getUserPrivateKeyPath();
|
||||||
return fs.readFileSync(userPrivateKey, 'utf-8');
|
return fs.readFileSync(userPrivateKey, 'utf-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createUserSSHKey() {
|
public async createUserSSHKey() {
|
||||||
if (this.existUserPublicKey() && this.existUserPrivateKey()) {
|
if (this.existUserPublicKey() && this.existUserPrivateKey()) {
|
||||||
// if both public and private key exists, stop
|
// if both public and private key exists, stop
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
publicKey,
|
publicKey,
|
||||||
privateKey,
|
privateKey,
|
||||||
} = await generateKeyPairSync('rsa', {
|
} = await generateKeyPairSync('rsa', {
|
||||||
modulusLength: 4096,
|
modulusLength: 4096,
|
||||||
publicKeyEncoding: {
|
publicKeyEncoding: {
|
||||||
type: 'pkcs1',
|
type: 'pkcs1',
|
||||||
format: 'pem',
|
format: 'pem',
|
||||||
},
|
},
|
||||||
privateKeyEncoding: {
|
privateKeyEncoding: {
|
||||||
type: 'pkcs1',
|
type: 'pkcs1',
|
||||||
format: 'pem',
|
format: 'pem',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const publicKeyFingerprint = sshpk.parseKey(publicKey, 'pem').toString('ssh');
|
const publicKeyFingerprint = sshpk.parseKey(publicKey, 'pem').toString('ssh');
|
||||||
const publicKeyStr = publicKeyFingerprint; // public key is public key fingerprint
|
const publicKeyStr = publicKeyFingerprint; // public key is public key fingerprint
|
||||||
const privateKeyStr = privateKey;
|
const privateKeyStr = privateKey;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 确保公/私钥目录存在
|
// 确保公/私钥目录存在
|
||||||
const publicKeyDir = path.dirname(this.getUserPublicKeyPath())
|
const publicKeyDir = path.dirname(this.getUserPublicKeyPath())
|
||||||
if (!fs.existsSync(publicKeyDir)) {
|
if (!fs.existsSync(publicKeyDir)) {
|
||||||
console.log(`Directory ${publicKeyDir} does not exist, creating it...`);
|
console.log(`Directory ${publicKeyDir} does not exist, creating it...`);
|
||||||
// 公钥与私钥的目录一样,所以只用创建一次
|
// 公钥与私钥的目录一样,所以只用创建一次
|
||||||
fs.mkdirSync(publicKeyDir, {recursive: true})
|
fs.mkdirSync(publicKeyDir, {recursive: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(this.getUserPublicKeyPath(), publicKeyStr);
|
fs.writeFileSync(this.getUserPublicKeyPath(), publicKeyStr);
|
||||||
fs.writeFileSync(this.getUserPrivateKeyPath(), privateKeyStr);
|
fs.writeFileSync(this.getUserPrivateKeyPath(), privateKeyStr);
|
||||||
// limit the permission of private key to prevent that the private key not works
|
// limit the permission of private key to prevent that the private key not works
|
||||||
fs.chmodSync(this.getUserPrivateKeyPath(), 0o600)
|
fs.chmodSync(this.getUserPrivateKeyPath(), 0o600)
|
||||||
console.log(`User's ssh key has been created.`)
|
console.log(`User's ssh key has been created.`)
|
||||||
// 更新local user private key path
|
// 更新local user private key path
|
||||||
this.updateLocalUserPrivateKeyPath(this.getUserPrivateKeyPath())
|
this.updateLocalUserPrivateKeyPath(this.getUserPrivateKeyPath())
|
||||||
console.log(`Update local user private key path.`)
|
console.log(`Update local user private key path.`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to write public/private key into the user(${this.username}) ssh public/key file: `, error);
|
console.error(`Failed to write public/private key into the user(${this.username}) ssh public/key file: `, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
268
src/utils.ts
268
src/utils.ts
@@ -1,135 +1,135 @@
|
|||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
generateKeyPairSync,
|
generateKeyPairSync,
|
||||||
} = require('node:crypto')
|
} = require('node:crypto')
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const cheerio = require('cheerio');
|
const cheerio = require('cheerio');
|
||||||
|
|
||||||
|
|
||||||
export function isWindows(): boolean {
|
export function isWindows(): boolean {
|
||||||
return os.platform() === 'win32';
|
return os.platform() === 'win32';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLinux(): boolean {
|
export function isLinux(): boolean {
|
||||||
return os.platform() === 'linux';
|
return os.platform() === 'linux';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMacOS(): boolean {
|
export function isMacOS(): boolean {
|
||||||
return os.platform() === 'darwin';
|
return os.platform() === 'darwin';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function fetch(url: string): Promise<string> {
|
export function fetch(url: string): Promise<string> {
|
||||||
// determine the library to use (based on the url protocol)
|
// determine the library to use (based on the url protocol)
|
||||||
const lib = url.startsWith('https://') ? https : http;
|
const lib = url.startsWith('https://') ? https : http;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
lib.get(url, (response) => {
|
lib.get(url, (response) => {
|
||||||
// make sure the status code is 200
|
// make sure the status code is 200
|
||||||
if (response.statusCode !== 200) {
|
if (response.statusCode !== 200) {
|
||||||
reject(new Error(`Failed to load page, status code: ${response.statusCode}`));
|
reject(new Error(`Failed to load page, status code: ${response.statusCode}`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = '';
|
let data = '';
|
||||||
response.on('data', (chunk) => {
|
response.on('data', (chunk) => {
|
||||||
data += chunk;
|
data += chunk;
|
||||||
});
|
});
|
||||||
response.on('end', () => {
|
response.on('end', () => {
|
||||||
resolve(data);
|
resolve(data);
|
||||||
});
|
});
|
||||||
}).on('error', (err) => {
|
}).on('error', (err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sleep = (ms: number) => {
|
export const Sleep = (ms: number) => {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getVsCodeCommitId(): Promise<string> {
|
export async function getVsCodeCommitId(): Promise<string> {
|
||||||
if (isLinux() || isMacOS()) {
|
if (isLinux() || isMacOS()) {
|
||||||
return new Promise<string>((resolve) => {
|
return new Promise<string>((resolve) => {
|
||||||
exec('code --version', (error, stdout, stderr) => {
|
exec('code --version', (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Error occurred:' + error.message);
|
console.error('Error occurred:' + error.message);
|
||||||
resolve("");
|
resolve("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
console.error('Error output:' + stderr);
|
console.error('Error output:' + stderr);
|
||||||
resolve("");
|
resolve("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const lines = stdout.trim().split('\n');
|
const lines = stdout.trim().split('\n');
|
||||||
if (lines.length > 1) {
|
if (lines.length > 1) {
|
||||||
const commitId = lines[1]; // 第二行是 commit ID
|
const commitId = lines[1]; // 第二行是 commit ID
|
||||||
resolve(commitId);
|
resolve(commitId);
|
||||||
} else {
|
} else {
|
||||||
console.error('Unexpected output format:' + stdout);
|
console.error('Unexpected output format:' + stdout);
|
||||||
resolve("");
|
resolve("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 获取vscode version
|
// 获取vscode version
|
||||||
const version = vscode.version
|
const version = vscode.version
|
||||||
|
|
||||||
// 根据version提取相应的release页面中的commitid
|
// 根据version提取相应的release页面中的commitid
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`https://github.com/microsoft/vscode/releases/tag/${version}`);
|
const { data } = await axios.get(`https://github.com/microsoft/vscode/releases/tag/${version}`);
|
||||||
|
|
||||||
// Load the HTML into cheerio
|
// Load the HTML into cheerio
|
||||||
const $ = cheerio.load(data);
|
const $ = cheerio.load(data);
|
||||||
// Find the <a> tag with the 'data-hovercard-type="commit"' attribute
|
// Find the <a> tag with the 'data-hovercard-type="commit"' attribute
|
||||||
const commitLink = $('a[data-hovercard-type="commit"]');
|
const commitLink = $('a[data-hovercard-type="commit"]');
|
||||||
// Extract the href attribute and commit hash
|
// Extract the href attribute and commit hash
|
||||||
const href = commitLink.attr('href'); // href example: /microsoft/vscode/commit/fabdb6a30b49f79a7aba0f2ad9df9b399473380f
|
const href = commitLink.attr('href'); // href example: /microsoft/vscode/commit/fabdb6a30b49f79a7aba0f2ad9df9b399473380f
|
||||||
const commitHash = href.split('/').pop();
|
const commitHash = href.split('/').pop();
|
||||||
|
|
||||||
return commitHash
|
return commitHash
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to get commit id: ' + error)
|
console.error('Failed to get commit id: ' + error)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function devstarDomain(): string | undefined {
|
export function devstarDomain(): string | undefined {
|
||||||
// 从用户配置中读取
|
// 从用户配置中读取
|
||||||
return vscode.workspace.getConfiguration('devstar').get('devstarDomain')
|
return vscode.workspace.getConfiguration('devstar').get('devstarDomain')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function showErrorNotification(message: string): Promise<void> {
|
export async function showErrorNotification(message: string): Promise<void> {
|
||||||
const selection = await vscode.window.showErrorMessage(message, 'Open Console', 'Report a problem',);
|
const selection = await vscode.window.showErrorMessage(message, 'Open Console', 'Report a problem',);
|
||||||
if (selection === 'Open Console') {
|
if (selection === 'Open Console') {
|
||||||
vscode.commands.executeCommand('workbench.action.toggleDevTools');
|
vscode.commands.executeCommand('workbench.action.toggleDevTools');
|
||||||
} else if (selection === 'Report a problem') {
|
} else if (selection === 'Report a problem') {
|
||||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://github.com/mengning/DevStar/issues/new'));
|
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://github.com/mengning/DevStar/issues/new'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function powershellVersion(): Promise<string> {
|
export async function powershellVersion(): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec('powershell -Command "$PSVersionTable.PSVersion.ToString()"', (error, stdout, stderr) => {
|
exec('powershell -Command "$PSVersionTable.PSVersion.ToString()"', (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(`Error executing PowerShell command: ${error.message}`);
|
reject(`Error executing PowerShell command: ${error.message}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
reject(`PowerShell command returned an error: ${stderr}`);
|
reject(`PowerShell command returned an error: ${stderr}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resolve(stdout.trim());
|
resolve(stdout.trim());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
@@ -1,47 +1,47 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
class QuickItem extends vscode.TreeItem {
|
class QuickItem extends vscode.TreeItem {
|
||||||
customChildren: QuickItem[] | undefined;
|
customChildren: QuickItem[] | undefined;
|
||||||
|
|
||||||
constructor(label: string, command?: string, args?: any, collapsibleState?: vscode.TreeItemCollapsibleState, children?: QuickItem[]) {
|
constructor(label: string, command?: string, args?: any, collapsibleState?: vscode.TreeItemCollapsibleState, children?: QuickItem[]) {
|
||||||
super(label, collapsibleState);
|
super(label, collapsibleState);
|
||||||
if (command) {
|
if (command) {
|
||||||
this.command = {
|
this.command = {
|
||||||
title: label,
|
title: label,
|
||||||
command,
|
command,
|
||||||
arguments: args,
|
arguments: args,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.customChildren = children;
|
this.customChildren = children;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class QuickAccessTreeProvider {
|
export default class QuickAccessTreeProvider {
|
||||||
getChildren(element: QuickItem) {
|
getChildren(element: QuickItem) {
|
||||||
if (element && element.customChildren) {
|
if (element && element.customChildren) {
|
||||||
return element.customChildren;
|
return element.customChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new QuickItem(
|
new QuickItem(
|
||||||
vscode.l10n.t('DevStar Home'),
|
vscode.l10n.t('DevStar Home'),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
vscode.TreeItemCollapsibleState.Expanded,
|
vscode.TreeItemCollapsibleState.Expanded,
|
||||||
[new QuickItem(vscode.l10n.t('Open'), 'devstar.showHome')]
|
[new QuickItem(vscode.l10n.t('Open'), 'devstar.showHome')]
|
||||||
),
|
),
|
||||||
new QuickItem(
|
new QuickItem(
|
||||||
vscode.l10n.t('Miscellaneous'),
|
vscode.l10n.t('Miscellaneous'),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
vscode.TreeItemCollapsibleState.Expanded,
|
vscode.TreeItemCollapsibleState.Expanded,
|
||||||
// [new QuickItem('Connect Remote Container', 'devstar.connectRemoteContainer')]
|
// [new QuickItem('Connect Remote Container', 'devstar.connectRemoteContainer')]
|
||||||
[new QuickItem(vscode.l10n.t('Clean'), 'devstar.clean')]
|
[new QuickItem(vscode.l10n.t('Clean'), 'devstar.clean')]
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTreeItem(element: QuickItem) {
|
getTreeItem(element: QuickItem) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1830
test/home.html
1830
test/home.html
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,24 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"lib": [
|
"lib": [
|
||||||
"ES6",
|
"ES6",
|
||||||
"DOM"
|
"DOM"
|
||||||
],
|
],
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"strict": true, /* enable all strict type-checking options */
|
"strict": true, /* enable all strict type-checking options */
|
||||||
/* Additional Checks */
|
/* Additional Checks */
|
||||||
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
"noUnusedParameters": true, /* Report errors on unused parameters. */
|
"noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||||
/* Emit */
|
/* Emit */
|
||||||
"outDir": "dist", /* Redirect output structure to the directory. */
|
"outDir": "dist", /* Redirect output structure to the directory. */
|
||||||
"removeComments": true, /* Do not emit comments to output. */
|
"removeComments": true, /* Do not emit comments to output. */
|
||||||
"noEmitOnError": true, /* Do not emit outputs if any errors were reported. */
|
"noEmitOnError": true, /* Do not emit outputs if any errors were reported. */
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.ts"
|
"**/*.ts"
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@@ -1,32 +1,32 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const packageConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
|
const packageConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
|
||||||
const externals = Object.keys(packageConfig.dependencies);
|
const externals = Object.keys(packageConfig.dependencies);
|
||||||
externals.push('vscode');
|
externals.push('vscode');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
entry: __dirname + '/src/main.ts',
|
entry: __dirname + '/src/main.ts',
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'extension.js',
|
filename: 'extension.js',
|
||||||
libraryTarget: 'commonjs2'
|
libraryTarget: 'commonjs2'
|
||||||
},
|
},
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
target: 'node',
|
target: 'node',
|
||||||
externals: externals,
|
externals: externals,
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.ts$/,
|
test: /\.ts$/,
|
||||||
loader: 'ts-loader',
|
loader: 'ts-loader',
|
||||||
exclude: /node_modules/
|
exclude: /node_modules/
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: [path.resolve('./node_modules'), path.resolve('./src')],
|
modules: [path.resolve('./node_modules'), path.resolve('./src')],
|
||||||
extensions: ['.ts', '.js']
|
extensions: ['.ts', '.js']
|
||||||
}
|
}
|
||||||
};
|
};
|
Reference in New Issue
Block a user