mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Compare commits
257 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72f6d8a006 | ||
|
|
86a019842f | ||
|
|
207a9a6a25 | ||
|
|
6e26261149 | ||
|
|
acd9fc8fd6 | ||
|
|
3432743f63 | ||
|
|
f45583c0f6 | ||
|
|
aecb0efbc0 | ||
|
|
86fcd05eff | ||
|
|
1f71ea301c | ||
|
|
a721ab559d | ||
|
|
0c0c87184c | ||
|
|
39900b7a92 | ||
|
|
6435540f35 | ||
|
|
3b38ba7e30 | ||
|
|
bc0753a95c | ||
|
|
76d6e93f7c | ||
|
|
f7cd25af71 | ||
|
|
858c1e826d | ||
|
|
2b0b529b21 | ||
|
|
ec0f7f992c | ||
|
|
3683aaaf2a | ||
|
|
6440bad9bb | ||
|
|
f8a6658128 | ||
|
|
1e00898105 | ||
|
|
3c647c4376 | ||
|
|
0a3d109073 | ||
|
|
4c4c22331d | ||
|
|
dcd1a175e4 | ||
|
|
2b2c912135 | ||
|
|
99de46adbd | ||
|
|
7fbc37058b | ||
|
|
24b3181cbc | ||
|
|
adacbdc4cf | ||
|
|
9bdfa57be6 | ||
|
|
540046ba00 | ||
|
|
9c67832880 | ||
|
|
28f1321ad7 | ||
|
|
92b0603968 | ||
|
|
ea2564b133 | ||
|
|
99e1bbf06f | ||
|
|
c0836409cc | ||
|
|
50b6789e51 | ||
|
|
b71432523d | ||
|
|
d380328f8b | ||
|
|
aa151b280f | ||
|
|
656d944894 | ||
|
|
0c3798ae26 | ||
|
|
e7ec278ef2 | ||
|
|
9df51b9936 | ||
|
|
8fce371e3f | ||
|
|
381a32929f | ||
|
|
eeb1f7cf3e | ||
|
|
694f34a4cd | ||
|
|
fbbb9ce529 | ||
|
|
9d730bd0b5 | ||
|
|
f941f9910b | ||
|
|
68e7a293ad | ||
|
|
30845cbd6d | ||
|
|
c52155b621 | ||
|
|
1a68f17650 | ||
|
|
13008cc2b9 | ||
|
|
9c1168ba3b | ||
|
|
89753577ab | ||
|
|
4f58f53e57 | ||
|
|
969936d98d | ||
|
|
21d09cb975 | ||
|
|
01957abf71 | ||
|
|
9e5bd182bb | ||
|
|
ee540ac89c | ||
|
|
5fd9d1b18f | ||
|
|
6fbb9c2773 | ||
|
|
6e439d66a8 | ||
|
|
c06bd0821b | ||
|
|
6751dffbc3 | ||
|
|
d244a14468 | ||
|
|
ada8cb2f08 | ||
|
|
cf6d02d2b4 | ||
|
|
3c7f2df156 | ||
|
|
5b234d5884 | ||
|
|
9d1587f008 | ||
|
|
c7423efe14 | ||
|
|
51abf123a9 | ||
|
|
6928904a26 | ||
|
|
c275f367da | ||
|
|
67ddf81562 | ||
|
|
6d77176b92 | ||
|
|
807d03725f | ||
|
|
4cf7f9ed66 | ||
|
|
1ab18113ee | ||
|
|
6d9efbd603 | ||
|
|
56d1a1c1af | ||
|
|
d965d4aef3 | ||
|
|
eccf3cf5fe | ||
|
|
5b8039379e | ||
|
|
83211d6e2d | ||
|
|
188cfdbd20 | ||
|
|
2b132f6b58 | ||
|
|
769a9d4699 | ||
|
|
2fc51ffe82 | ||
|
|
c963e6ec08 | ||
|
|
21cf89fb7e | ||
|
|
a889d017f5 | ||
|
|
32047d5557 | ||
|
|
196b3752a9 | ||
|
|
c76e3ff0c9 | ||
|
|
ede827ee82 | ||
|
|
efc8182954 | ||
|
|
154b75a0de | ||
|
|
9b4931bb0e | ||
|
|
b53d1cee4a | ||
|
|
4a88adffd2 | ||
|
|
587abd43c2 | ||
|
|
a61b85c9ff | ||
|
|
d086b5b01e | ||
|
|
8da27190a2 | ||
|
|
c3d151fbee | ||
|
|
ca39cbe6ab | ||
|
|
2f0dbb633d | ||
|
|
f316c27098 | ||
|
|
1b7b54ce14 | ||
|
|
53ec7585a9 | ||
|
|
0f2b463536 | ||
|
|
0c3c714be1 | ||
|
|
39ca386d2a | ||
|
|
b57cae5b60 | ||
|
|
238d643a8e | ||
|
|
7461cf844d | ||
|
|
f780db907d | ||
|
|
d533af3019 | ||
|
|
92c8d890c4 | ||
|
|
69849de6f0 | ||
|
|
7fe3df8259 | ||
|
|
d99201002d | ||
|
|
8828758b2f | ||
|
|
921beebd79 | ||
|
|
ca900464e5 | ||
|
|
3792a6328f | ||
|
|
047c51921b | ||
|
|
26f833f728 | ||
|
|
66632e6262 | ||
|
|
decba446dd | ||
|
|
6f9991e22b | ||
|
|
5613a97fae | ||
|
|
eb82cd3f4b | ||
|
|
648174e91d | ||
|
|
fea0fb13f6 | ||
|
|
0833de1e7c | ||
|
|
3c3c5f7348 | ||
|
|
4594943b53 | ||
|
|
42fa5c3275 | ||
|
|
3633a21413 | ||
|
|
71fbe2ed53 | ||
|
|
da4f9152a3 | ||
|
|
54e3df8e84 | ||
|
|
9efe275c39 | ||
|
|
27983d4c66 | ||
|
|
6f2d29ca57 | ||
|
|
cdf173c4db | ||
|
|
991b081977 | ||
|
|
3faadb72a3 | ||
|
|
14262151e9 | ||
|
|
1c53a209bc | ||
|
|
f1a13fae39 | ||
|
|
b098ce64b5 | ||
|
|
b96ea07d8f | ||
|
|
48ef272c66 | ||
|
|
ddb6129d8b | ||
|
|
309bb51812 | ||
|
|
c013e3fc27 | ||
|
|
9744d7796c | ||
|
|
9b1eb53665 | ||
|
|
b68b655fa5 | ||
|
|
8b206a4d52 | ||
|
|
16f24d8c6a | ||
|
|
021c01e0b6 | ||
|
|
8322e5dc83 | ||
|
|
62b8ff4972 | ||
|
|
6d679b6416 | ||
|
|
0e81d04b98 | ||
|
|
ac1237d51c | ||
|
|
8e5da8aa36 | ||
|
|
6098bffc99 | ||
|
|
cc78d6a8f0 | ||
|
|
0a1c2583cc | ||
|
|
9d3f12d0b7 | ||
|
|
aae013d498 | ||
|
|
0fa23eb3b5 | ||
|
|
f4a4127471 | ||
|
|
c7799168b0 | ||
|
|
59ad8b3e61 | ||
|
|
f8f64340f6 | ||
|
|
dc7e6f59bd | ||
|
|
6147e1cba4 | ||
|
|
de69e73a9d | ||
|
|
24f6cd2e5b | ||
|
|
cabbbb56f2 | ||
|
|
1b616acfdb | ||
|
|
cbf3cd7445 | ||
|
|
9e6056968b | ||
|
|
6e9e97f711 | ||
|
|
11aa2b73b4 | ||
|
|
22f85ad4ff | ||
|
|
3c0d819911 | ||
|
|
351ab2f40f | ||
|
|
286c021df9 | ||
|
|
ff979f90d1 | ||
|
|
347c193455 | ||
|
|
1e62030581 | ||
|
|
32c3a13f7b | ||
|
|
81008d3803 | ||
|
|
ab9fceec70 | ||
|
|
d2bdd2bace | ||
|
|
e2b52b97c8 | ||
|
|
df8f5ae3a6 | ||
|
|
30e8edd875 | ||
|
|
6d6abdff7d | ||
|
|
e714c876c2 | ||
|
|
3db33de69f | ||
|
|
0835d3ed0f | ||
|
|
3e860692a2 | ||
|
|
95b024ed66 | ||
|
|
16329d6749 | ||
|
|
1ce24fae05 | ||
|
|
826a0cf9ec | ||
|
|
399bac33f4 | ||
|
|
171f091c88 | ||
|
|
7d5ecfe905 | ||
|
|
1796b519e5 | ||
|
|
c334a95d35 | ||
|
|
5a275209cc | ||
|
|
9c0f415bd9 | ||
|
|
a69032e317 | ||
|
|
7176c7f42f | ||
|
|
f5a16de2a4 | ||
|
|
2a7483c036 | ||
|
|
ae908530e2 | ||
|
|
b3a01fcf77 | ||
|
|
449a46d7fc | ||
|
|
b3121fae22 | ||
|
|
f95cb5f5d3 | ||
|
|
5f8180ebbf | ||
|
|
f409abfc01 | ||
|
|
9f0584f88f | ||
|
|
3cf48fb207 | ||
|
|
3084867d7e | ||
|
|
ac78822d90 | ||
|
|
aa4045c8a9 | ||
|
|
2a6fcee913 | ||
|
|
6d94d79527 | ||
|
|
eabacae0c0 | ||
|
|
84a7d1916a | ||
|
|
b238819c89 | ||
|
|
b0cab3125e | ||
|
|
0043a7f93b | ||
|
|
6eb88924f6 | ||
|
|
ac71c6f06d |
@@ -3,7 +3,7 @@
|
||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-10
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-12
|
||||
|
||||
ARG TARGET_DISPLAY=":1"
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ This repository includes configuration for a development container for working w
|
||||
|
||||
## Quick start - local
|
||||
|
||||
1. Install Docker Desktop or Docker on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.)
|
||||
1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.)
|
||||
|
||||
2. [Docker Desktop] If you are not using the new WSL2 Docker Desktop engine, increase the resources allocated to Docker Desktop to at least **4 Cores and 4 GB of RAM (8 GB recommended)**. Right-click on the Docker status bar item, go to **Preferences/Settings > Resources > Advanced** to do so.
|
||||
2. **Important**: Docker needs at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run full build. If you on macOS, or using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item, going to **Preferences/Settings > Resources > Advanced**.
|
||||
|
||||
> **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar.
|
||||
|
||||
@@ -44,7 +44,7 @@ Next: **[Try it out!](#try-it)**
|
||||
|
||||
3. Press <kbd>Ctrl/Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> and select **Codespaces: Create New Codespace**.
|
||||
|
||||
4. Use default settings, select a plan, and then enter the repository URL `https://github.com/microsoft/vscode` (or a branch or PR URL) in the input box when prompted.
|
||||
4. Use default settings (which should include **Standard** 4 core, 8 GB RAM Codespace), select a plan, and then enter the repository URL `https://github.com/microsoft/vscode` (or a branch or PR URL) in the input box when prompted.
|
||||
|
||||
5. After the container is running, open a web browser and go to [http://localhost:6080](http://localhost:6080) or use a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to connect to `localhost:5901` and enter `vscode` as the password.
|
||||
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
}
|
||||
},
|
||||
"overrideCommand": false,
|
||||
"runArgs": ["--init"],
|
||||
"runArgs": [
|
||||
"--init",
|
||||
// seccomp=unconfined is required for Chrome sandboxing
|
||||
"--security-opt", "seccomp=unconfined"
|
||||
],
|
||||
|
||||
"settings": {
|
||||
// zsh is also available
|
||||
|
||||
@@ -764,6 +764,18 @@
|
||||
"*" // node modules
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/code/browser/**",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"vs/css!./**/*",
|
||||
"**/{vs,sql}/base/**/{common,browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser}/**",
|
||||
"**/{vs,sql}/code/**/{common,browser}/**",
|
||||
"**/{vs,sql}/workbench/workbench.web.api"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/{vs,sql}/code/node/**",
|
||||
"restrictions": [
|
||||
@@ -834,6 +846,18 @@
|
||||
"**/{vs,sql}/workbench/workbench.common.main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/src/{vs,sql}/workbench/workbench.web.api.ts",
|
||||
"restrictions": [
|
||||
"vs/nls",
|
||||
"**/{vs,sql}/base/**/{common,browser}/**",
|
||||
"**/{vs,sql}/base/parts/**/{common,browser}/**",
|
||||
"**/{vs,sql}/platform/**/{common,browser}/**",
|
||||
"**/{vs,sql}/editor/**",
|
||||
"**/{vs,sql}/workbench/**/{common,browser}/**",
|
||||
"**/{vs,sql}/workbench/workbench.web.main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/src/{vs,sql}/workbench/workbench.sandbox.main.ts",
|
||||
"restrictions": [
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,6 +24,7 @@ out-vscode-reh-web-min/
|
||||
out-vscode-reh-web-pkg/
|
||||
out-vscode-web/
|
||||
out-vscode-web-min/
|
||||
out-vscode-web-pkg/
|
||||
src/vs/server
|
||||
resources/server
|
||||
build/node_modules
|
||||
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -4,7 +4,6 @@
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"EditorConfig.EditorConfig",
|
||||
"msjsdiag.debugger-for-chrome",
|
||||
"ms-vscode.vscode-github-issue-notebooks"
|
||||
"msjsdiag.debugger-for-chrome"
|
||||
]
|
||||
}
|
||||
|
||||
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
@@ -90,9 +90,10 @@
|
||||
"port": 9222,
|
||||
"timeout": 20000,
|
||||
"env": {
|
||||
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null
|
||||
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null,
|
||||
"VSCODE_SKIP_PRELAUNCH": "1"
|
||||
},
|
||||
"breakOnLoad": false,
|
||||
"cleanUp": "wholeBrowser",
|
||||
"urlFilter": "*workbench.html*",
|
||||
"runtimeArgs": [
|
||||
"--inspect=5875",
|
||||
@@ -105,7 +106,8 @@
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
"browserLaunchLocation": "workspace"
|
||||
"browserLaunchLocation": "workspace",
|
||||
"preLaunchTask": "Ensure Prelaunch Dependencies",
|
||||
},
|
||||
{
|
||||
"type": "chrome",
|
||||
|
||||
38
.vscode/notebooks/api.github-issues
vendored
Normal file
38
.vscode/notebooks/api.github-issues
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "#### Config",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"July 2020\"",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "### Finalization",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repo $milestone label:api-finalization",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "### Proposals",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repo $milestone is:open label:api-proposal ",
|
||||
"editable": true
|
||||
}
|
||||
]
|
||||
17
.vscode/notebooks/inbox.github-issues
vendored
17
.vscode/notebooks/inbox.github-issues
vendored
@@ -2,13 +2,24 @@
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "##### `Config`: defines the inbox query"
|
||||
"value": "##### `Config`: defines the inbox query",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item "
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "## Inbox tracking and Issue triage"
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "New issues or pull requests submitted by the community are initially triaged by an [automatic classification bot](https://github.com/microsoft/vscode-github-triage-actions/tree/master/classifier-deep). Issues that the bot does not correctly triage are then triaged by a team member. The team rotates the inbox tracker on a weekly basis.\n\nA [mirror](https://github.com/JacksonKearl/testissues/issues) of the VS Code issue stream is available with details about how the bot classifies issues, including feature-area classifications and confidence ratings. Per-category confidence thresholds and feature-area ownership data is maintained in [.github/classifier.json](https://github.com/microsoft/vscode/blob/master/.github/classifier.json). \n\n💡 The bot is being run through a GitHub action that runs every 30 minutes. Give the bot the opportunity to classify an issue before doing it manually.\n\n### Inbox Tracking\n\nThe inbox tracker is responsible for the [global inbox](https://github.com/Microsoft/vscode/issues?utf8=%E2%9C%93&q=is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Atestplan-item+-label%3Aplan-item) containing all **open issues and pull requests** that\n- are neither **feature requests** nor **test plan items** nor **plan items** and\n- have **no owner assignment**.\n\nThe **inbox tracker** may perform any step described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) but its main responsibility is to route issues to the actual feature area owner.\n\nFeature area owners track the **feature area inbox** containing all **open issues and pull requests** that\n- are personally assigned to them and are not assigned to any milestone\n- are labeled with their feature area label and are not assigned to any milestone.\nThis secondary triage may involve any of the steps described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) and results in a fully triaged or closed issue.\n\nThe [github triage extension](https://github.com/microsoft/vscode-github-triage-extension) can be used to assist with triaging — it provides a \"Command Palette\"-style list of triaging actions like assignment, labeling, and triggers for various bot actions."
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
@@ -18,7 +29,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$inbox -label:\"needs more info\"",
|
||||
"value": "$inbox -label:\"needs more info\" -label:emmet",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
@@ -30,7 +41,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$inbox",
|
||||
"value": "$inbox -label:emmet",
|
||||
"editable": true
|
||||
}
|
||||
]
|
||||
2
.vscode/notebooks/my-work.github-issues
vendored
2
.vscode/notebooks/my-work.github-issues
vendored
@@ -20,7 +20,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos $milestone assignee:@me is:open\n",
|
||||
"value": "$repos $milestone assignee:@me is:open",
|
||||
"editable": false
|
||||
},
|
||||
{
|
||||
|
||||
55
.vscode/notebooks/verification.github-issues
vendored
Normal file
55
.vscode/notebooks/verification.github-issues
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
[
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "### Bug Verification Queries\n\nBefore shipping we want to verify _all_ bugs. That means when a bug is fixed we check that the fix actually works. It's always best to start with bugs that you have filed and the proceed with bugs that have been filed from users outside the development team. ",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "#### Config: update list of `repos` and the `milestone`",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks \n$milestone=milestone:\"June 2020\"",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "### Bugs You Filed",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate author:@me",
|
||||
"editable": false
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "### Bugs From Outside",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate -author:@me -assignee:@me label:bug -label:verified -author:@me -author:aeschli -author:alexdima -author:alexr00 -author:bpasero -author:chrisdias -author:chrmarti -author:connor4312 -author:dbaeumer -author:deepak1556 -author:eamodio -author:egamma -author:gregvanl -author:isidorn -author:JacksonKearl -author:joaomoreno -author:jrieken -author:lramos15 -author:lszomoru -author:misolori -author:mjbvz -author:rebornix -author:RMacfarlane -author:roblourens -author:sana-ajani -author:sandy081 -author:sbatten -author:Tyriar -author:weinand",
|
||||
"editable": false
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
"language": "markdown",
|
||||
"value": "### All"
|
||||
},
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repos $milestone is:closed -assignee:@me label:bug -label:verified -label:*duplicate",
|
||||
"editable": false
|
||||
}
|
||||
]
|
||||
25
.vscode/searches/es6.code-search
vendored
25
.vscode/searches/es6.code-search
vendored
@@ -2,7 +2,7 @@
|
||||
# Flags: CaseSensitive WordMatch
|
||||
# ContextLines: 2
|
||||
|
||||
16 results - 5 files
|
||||
14 results - 4 files
|
||||
|
||||
src/vs/base/browser/dom.ts:
|
||||
81 };
|
||||
@@ -34,24 +34,11 @@ src/vs/base/common/arrays.ts:
|
||||
420 */
|
||||
421 export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
|
||||
|
||||
560
|
||||
561 /**
|
||||
562: * @deprecated ES6: use `Array.find`
|
||||
563 */
|
||||
564 export function find<T>(arr: ArrayLike<T>, predicate: (value: T, index: number, arr: ArrayLike<T>) => any): T | undefined {
|
||||
|
||||
src/vs/base/common/map.ts:
|
||||
11
|
||||
12 /**
|
||||
13: * @deprecated ES6: use `[...SetOrMap.values()]`
|
||||
14 */
|
||||
15 export function values<V = any>(set: Set<V>): V[];
|
||||
|
||||
22
|
||||
23 /**
|
||||
24: * @deprecated ES6: use `[...map.keys()]`
|
||||
25 */
|
||||
26 export function keys<K, V>(map: Map<K, V>): K[] {
|
||||
569
|
||||
570 /**
|
||||
571: * @deprecated ES6: use `Array.find`
|
||||
572 */
|
||||
573 export function find<T>(arr: ArrayLike<T>, predicate: (value: T, index: number, arr: ArrayLike<T>) => any): T | undefined {
|
||||
|
||||
src/vs/base/common/objects.ts:
|
||||
115
|
||||
|
||||
93
.vscode/tasks.json
vendored
93
.vscode/tasks.json
vendored
@@ -3,12 +3,8 @@
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watchd",
|
||||
"label": "Build VS Code",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"script": "watch-clientd",
|
||||
"label": "Build VS Code Core",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
@@ -31,6 +27,71 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch-extensionsd",
|
||||
"label": "Build VS Code Extensions",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"applyTo": "closedDocuments",
|
||||
"fileLocation": [
|
||||
"absolute"
|
||||
],
|
||||
"pattern": {
|
||||
"regexp": "Error: ([^(]+)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\): (.*)$",
|
||||
"file": 1,
|
||||
"location": 2,
|
||||
"message": 3
|
||||
},
|
||||
"background": {
|
||||
"beginsPattern": "Starting compilation",
|
||||
"endsPattern": "Finished compilation"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build VS Code",
|
||||
"dependsOn": [
|
||||
"Build VS Code Core",
|
||||
"Build VS Code Extensions"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "kill-watch-clientd",
|
||||
"label": "Kill Build VS Code Core",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "kill-watch-extensionsd",
|
||||
"label": "Kill Build VS Code Extensions",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"label": "Kill Build VS Code",
|
||||
"dependsOn": [
|
||||
"Kill Build VS Code Core",
|
||||
"Kill Build VS Code Extensions"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "strict-vscode-watch",
|
||||
@@ -45,16 +106,6 @@
|
||||
"applyTo": "allDocuments"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "kill-watchd",
|
||||
"label": "Kill Build VS Code",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch-webd",
|
||||
@@ -149,6 +200,14 @@
|
||||
"source": "eslint",
|
||||
"base": "$eslint-stylish"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"command": "node build/lib/prelaunch.js",
|
||||
"label": "Ensure Prelaunch Dependencies",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,5 +1,25 @@
|
||||
# Change Log
|
||||
|
||||
## Version 1.20.1
|
||||
* Release date: July 17, 2020
|
||||
* Release status: General Availability
|
||||
* Fix bug #11372 Object Explorer drag-and-drop table incorrectly wraps table names [#11372](https://github.com/microsoft/azuredatastudio/issues/11372)
|
||||
* Fix bug #11356 Dark theme is now the default theme [#11356](https://github.com/microsoft/azuredatastudio/issues/11356)
|
||||
* Known Issues:
|
||||
* Some users have reported connection errors from the new Microsoft.Data.SqlClient v2.0.0 included in this release. Users have found [following these instructions](https://github.com/microsoft/azuredatastudio/issues/11367#issuecomment-659614111) to successfully connect. This issue was caused by a client driver update which fixed an issue where TLS encryption wasn't enforced correctly. See https://github.com/dotnet/SqlClient/blob/master/release-notes/2.0/2.0.0.md#breaking-changes-1 and https://docs.microsoft.com/en-us/sql/relational-databases/native-client/features/using-encryption-without-validation for more information.
|
||||
|
||||
## Version 1.20.0
|
||||
* Release date: July 15, 2020
|
||||
* Release status: General Availability
|
||||
* Feature Tour
|
||||
* New Notebook Features
|
||||
* Header support in Markdown Toolbar
|
||||
* Side-by-side Markdown preview in Text Cells
|
||||
* Drag and drop columns and tables into Query Editor
|
||||
* Azure Account icon added to Activity Bar
|
||||
* Address issues in [July 2020 Milestone](https://github.com/microsoft/azuredatastudio/milestone/57?closed=1)
|
||||
* Bug fixes
|
||||
|
||||
## Version 1.19.0
|
||||
* Release date: June 15, 2020
|
||||
* Release status: General Availability
|
||||
|
||||
14
README.md
14
README.md
@@ -129,10 +129,10 @@ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the [Source EULA](LICENSE.txt).
|
||||
|
||||
[win-user]: https://go.microsoft.com/fwlink/?linkid=2132348
|
||||
[win-system]: https://go.microsoft.com/fwlink/?linkid=2132347
|
||||
[win-zip]: https://go.microsoft.com/fwlink/?linkid=2132518
|
||||
[osx-zip]: https://go.microsoft.com/fwlink/?linkid=2132519
|
||||
[linux-zip]: https://go.microsoft.com/fwlink/?linkid=2132349
|
||||
[linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2132351
|
||||
[linux-deb]: https://go.microsoft.com/fwlink/?linkid=2132350
|
||||
[win-user]: https://go.microsoft.com/fwlink/?linkid=2135512
|
||||
[win-system]: https://go.microsoft.com/fwlink/?linkid=2135513
|
||||
[win-zip]: https://go.microsoft.com/fwlink/?linkid=2135514
|
||||
[osx-zip]: https://go.microsoft.com/fwlink/?linkid=2135266
|
||||
[linux-zip]: https://go.microsoft.com/fwlink/?linkid=2135267
|
||||
[linux-rpm]: https://go.microsoft.com/fwlink/?linkid=2135268
|
||||
[linux-deb]: https://go.microsoft.com/fwlink/?linkid=2135515
|
||||
|
||||
@@ -27,11 +27,11 @@ steps:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '10.15.3'
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||
inputs:
|
||||
versionSpec: '1.x'
|
||||
versionSpec: "1.x"
|
||||
|
||||
- task: AzureKeyVault@1
|
||||
displayName: 'Azure Key Vault: Get Secrets'
|
||||
@@ -131,9 +131,11 @@ steps:
|
||||
|
||||
# - script: |
|
||||
# set -e
|
||||
# node ./node_modules/playwright/install.js
|
||||
# VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/azuredatastudio-reh-web-darwin" \
|
||||
# yarn smoketest --web --headless --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
||||
# displayName: Run smoke tests (Browser)
|
||||
# continueOnError: true
|
||||
# condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||
|
||||
- script: |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '10.15.1'
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||
inputs:
|
||||
|
||||
@@ -24,7 +24,7 @@ steps:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '10.15.1'
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||
inputs:
|
||||
|
||||
@@ -36,6 +36,18 @@ function updateDTSFile(outPath: string, tag: string) {
|
||||
fs.writeFileSync(outPath, newContent);
|
||||
}
|
||||
|
||||
function repeat(str: string, times: number): string {
|
||||
const result = new Array(times);
|
||||
for (let i = 0; i < times; i++) {
|
||||
result[i] = str;
|
||||
}
|
||||
return result.join('');
|
||||
}
|
||||
|
||||
function convertTabsToSpaces(str: string): string {
|
||||
return str.replace(/^\t+/gm, value => repeat(' ', value.length));
|
||||
}
|
||||
|
||||
function getNewFileContent(content: string, tag: string) {
|
||||
const oldheader = [
|
||||
`/*---------------------------------------------------------------------------------------------`,
|
||||
@@ -44,7 +56,7 @@ function getNewFileContent(content: string, tag: string) {
|
||||
` *--------------------------------------------------------------------------------------------*/`
|
||||
].join('\n');
|
||||
|
||||
return getNewFileHeader(tag) + content.slice(oldheader.length);
|
||||
return convertTabsToSpaces(getNewFileHeader(tag) + content.slice(oldheader.length));
|
||||
}
|
||||
|
||||
function getNewFileHeader(tag: string) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
resources:
|
||||
containers:
|
||||
- container: linux-x64
|
||||
image: sqltoolscontainers.azurecr.io/linux-build-agent:1
|
||||
image: sqltoolscontainers.azurecr.io/linux-build-agent:2
|
||||
endpoint: ContainerRegistry
|
||||
|
||||
jobs:
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
steps:
|
||||
- template: linux/sql-product-build-linux.yml
|
||||
parameters:
|
||||
extensionsToUnitTest: ["admin-tool-ext-win", "agent", "azurecore", "cms", "dacpac", "import", "schema-compare", "notebook", "resource-deployment", "machine-learning", "sql-database-projects"]
|
||||
extensionsToUnitTest: ["admin-tool-ext-win", "agent", "azdata", "azurecore", "cms", "dacpac", "import", "schema-compare", "notebook", "resource-deployment", "machine-learning", "sql-database-projects"]
|
||||
timeoutInMinutes: 70
|
||||
|
||||
- job: LinuxWeb
|
||||
@@ -108,10 +108,3 @@ jobs:
|
||||
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
schedules:
|
||||
- cron: "0 5 * * Mon-Fri"
|
||||
displayName: Mon-Fri at 5AM UTC
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
|
||||
@@ -15,7 +15,7 @@ steps:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "10.15.1"
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||
inputs:
|
||||
|
||||
@@ -21,7 +21,7 @@ steps:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "10.15.1"
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||
inputs:
|
||||
@@ -103,6 +103,17 @@ steps:
|
||||
env:
|
||||
VSCODE_MIXIN_PASSWORD: $(github-distro-mixin-password)
|
||||
|
||||
- task: UniversalPackages@0
|
||||
displayName: Download SAW Python package
|
||||
inputs:
|
||||
command: 'download'
|
||||
downloadDirectory: '$(agent.builddirectory)\azuredatastudio-win32-x64\resources\app\ads-python'
|
||||
feedsToUse: 'internal'
|
||||
vstsFeed: '2191dd5f-4aec-491b-ac50-568bbc331c8a'
|
||||
vstsFeedPackage: '2e355f03-a97e-499a-949b-f02d62b6160c'
|
||||
vstsPackageVersion: '*'
|
||||
condition: and(succeeded(), eq(variables['VSCODE_QUALITY'], 'saw'))
|
||||
|
||||
# - powershell: | @anthonydresser unit tests timeout never existing the node process
|
||||
# . build/azure-pipelines/win32/exec.ps1
|
||||
# $ErrorActionPreference = "Stop"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "10.15.1"
|
||||
versionSpec: "12.13.0"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||
inputs:
|
||||
|
||||
@@ -171,8 +171,8 @@ gulp.task(compileExtensionsBuildLegacyTask);
|
||||
const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions'));
|
||||
const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series(
|
||||
cleanExtensionsBuildTask,
|
||||
task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream().pipe(gulp.dest('.build'))),
|
||||
task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build')))
|
||||
task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream(false).pipe(gulp.dest('.build'))),
|
||||
task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build'))),
|
||||
));
|
||||
|
||||
gulp.task(compileExtensionsBuildTask);
|
||||
|
||||
@@ -42,8 +42,8 @@ const indentationFilter = [
|
||||
'**',
|
||||
|
||||
// except specific files
|
||||
'!ThirdPartyNotices.txt',
|
||||
'!LICENSE.{txt,rtf}',
|
||||
'!**/ThirdPartyNotices.txt',
|
||||
'!**/LICENSE.{txt,rtf}',
|
||||
'!LICENSES.chromium.html',
|
||||
'!**/LICENSE',
|
||||
'!src/vs/nls.js',
|
||||
|
||||
@@ -36,23 +36,6 @@ const { compileBuildTask } = require('./gulpfile.compile');
|
||||
const { compileExtensionsBuildTask } = require('./gulpfile.extensions');
|
||||
|
||||
const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
|
||||
const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n));
|
||||
const nodeModules = [ // {{SQL CARBON EDIT}}
|
||||
'electron',
|
||||
'original-fs',
|
||||
'rxjs/Observable',
|
||||
'rxjs/add/observable/fromPromise',
|
||||
'rxjs/Subject',
|
||||
'rxjs/Observer',
|
||||
'slickgrid/lib/jquery.event.drag-2.3.0',
|
||||
'slickgrid/lib/jquery-ui-1.9.2',
|
||||
'slickgrid/slick.core',
|
||||
'slickgrid/slick.grid',
|
||||
'slickgrid/slick.editors',
|
||||
'slickgrid/slick.dataview']
|
||||
.concat(Object.keys(product.dependencies || {}))
|
||||
.concat(_.uniq(productionDependencies.map(d => d.name)))
|
||||
.concat(baseModules);
|
||||
|
||||
// Build
|
||||
const vscodeEntryPoints = _.flatten([
|
||||
@@ -75,6 +58,7 @@ const vscodeResources = [
|
||||
'out-build/paths.js',
|
||||
'out-build/vs/**/*.{svg,png,html}',
|
||||
'!out-build/vs/code/browser/**/*.html',
|
||||
'!out-build/vs/editor/standalone/**/*.svg',
|
||||
'out-build/vs/base/common/performance.js',
|
||||
'out-build/vs/base/node/languagePacks.js',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}',
|
||||
@@ -93,7 +77,6 @@ const vscodeResources = [
|
||||
'out-build/vs/code/electron-browser/workbench/**',
|
||||
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
||||
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
||||
'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
|
||||
'out-build/sql/workbench/electron-browser/splashscreen/*', // {{SQL CARBON EDIT}} STart
|
||||
'out-build/sql/**/*.{svg,png,cur,html}',
|
||||
'out-build/sql/base/browser/ui/table/media/*.{gif,png,svg}',
|
||||
@@ -113,6 +96,7 @@ const vscodeResources = [
|
||||
'out-build/sql/media/icons/*.svg',
|
||||
'out-build/sql/workbench/parts/notebook/media/**/*.svg',
|
||||
'out-build/sql/setup.js', // {{SQL CARBON EDIT}} end
|
||||
'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.js',
|
||||
'out-build/vs/platform/auth/common/auth.css',
|
||||
'!**/test/**'
|
||||
];
|
||||
@@ -123,7 +107,7 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
|
||||
src: 'out-build',
|
||||
entryPoints: vscodeEntryPoints,
|
||||
resources: vscodeResources,
|
||||
loaderConfig: common.loaderConfig(nodeModules),
|
||||
loaderConfig: common.loaderConfig(),
|
||||
out: 'out-vscode',
|
||||
bundleInfo: undefined
|
||||
})
|
||||
@@ -134,12 +118,6 @@ const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcem
|
||||
const minifyVSCodeTask = task.define('minify-vscode', task.series(
|
||||
optimizeVSCodeTask,
|
||||
util.rimraf('out-vscode-min'),
|
||||
() => {
|
||||
const fullpath = path.join(process.cwd(), 'out-vscode/bootstrap-window.js');
|
||||
const contents = fs.readFileSync(fullpath).toString();
|
||||
const newContents = contents.replace('[/*BUILD->INSERT_NODE_MODULES*/]', JSON.stringify(nodeModules));
|
||||
fs.writeFileSync(fullpath, newContents);
|
||||
},
|
||||
common.minifyTask('out-vscode', `${sourceMappingURLBase}/core`)
|
||||
));
|
||||
gulp.task(minifyVSCodeTask);
|
||||
|
||||
@@ -94,8 +94,8 @@ function buildWin32Setup(arch, target) {
|
||||
IncompatibleTargetAppId: { 'ia32': product.win32AppId, 'x64': product.win32x64AppId, 'arm64': product.win32arm64AppId }[arch],
|
||||
IncompatibleArchAppId: { 'ia32': x64AppId, 'x64': ia32AppId, 'arm64': ia32AppId }[arch],
|
||||
AppUserId: product.win32AppUserModelId,
|
||||
ArchitecturesAllowed: { 'ia32': '', 'x64': 'x64', 'arm64': '' }[arch],
|
||||
ArchitecturesInstallIn64BitMode: { 'ia32': '', 'x64': 'x64', 'arm64': '' }[arch],
|
||||
ArchitecturesAllowed: { 'ia32': '', 'x64': 'x64', 'arm64': 'arm64' }[arch],
|
||||
ArchitecturesInstallIn64BitMode: { 'ia32': '', 'x64': 'x64', 'arm64': 'arm64' }[arch],
|
||||
SourceDir: sourcePath,
|
||||
RepoDir: repoPath,
|
||||
OutputDir: outputPath,
|
||||
|
||||
@@ -100,7 +100,7 @@ function writeControlFile(control) {
|
||||
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
|
||||
}
|
||||
|
||||
function main() {
|
||||
exports.getBuiltInExtensions = function getBuiltInExtensions() {
|
||||
log('Syncronizing built-in extensions...');
|
||||
log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`);
|
||||
|
||||
@@ -116,14 +116,16 @@ function main() {
|
||||
|
||||
writeControlFile(control);
|
||||
|
||||
es.merge(streams)
|
||||
.on('error', err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
})
|
||||
.on('end', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
es.merge(streams)
|
||||
.on('error', reject)
|
||||
.on('end', resolve);
|
||||
});
|
||||
};
|
||||
|
||||
main();
|
||||
if (require.main === module) {
|
||||
exports.getBuiltInExtensions().then(() => process.exit(0)).catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ const reporter_1 = require("./reporter");
|
||||
const util = require("./util");
|
||||
const fancyLog = require("fancy-log");
|
||||
const ansiColors = require("ansi-colors");
|
||||
const os = require("os");
|
||||
const watch = require('./watch');
|
||||
const reporter = reporter_1.createReporter();
|
||||
function getTypeScriptCompilerOptions(src) {
|
||||
@@ -69,6 +70,9 @@ function createCompile(src, build, emitError) {
|
||||
}
|
||||
function compileTask(src, out, build) {
|
||||
return function () {
|
||||
if (os.totalmem() < 4000000000) {
|
||||
throw new Error('compilation requires 4GB of RAM');
|
||||
}
|
||||
const compile = createCompile(src, build, true);
|
||||
const srcPipe = gulp.src(`${src}/**`, { base: `${src}` });
|
||||
let generator = new MonacoGenerator(false);
|
||||
|
||||
@@ -18,6 +18,7 @@ import { createReporter } from './reporter';
|
||||
import * as util from './util';
|
||||
import * as fancyLog from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
import * as os from 'os';
|
||||
import ts = require('typescript');
|
||||
|
||||
const watch = require('./watch');
|
||||
@@ -81,6 +82,11 @@ function createCompile(src: string, build: boolean, emitError?: boolean) {
|
||||
export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream {
|
||||
|
||||
return function () {
|
||||
|
||||
if (os.totalmem() < 4_000_000_000) {
|
||||
throw new Error('compilation requires 4GB of RAM');
|
||||
}
|
||||
|
||||
const compile = createCompile(src, build, true);
|
||||
const srcPipe = gulp.src(`${src}/**`, { base: `${src}` });
|
||||
let generator = new MonacoGenerator(false);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.translatePackageJSON = exports.packageRebuildExtensionsStream = exports.cleanRebuildExtensions = exports.packageExternalExtensionsStream = exports.scanBuiltinExtensions = exports.packageMarketplaceWebExtensionsStream = exports.packageMarketplaceExtensionsStream = exports.packageLocalWebExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0;
|
||||
exports.translatePackageJSON = exports.packageRebuildExtensionsStream = exports.cleanRebuildExtensions = exports.packageExternalExtensionsStream = exports.scanBuiltinExtensions = exports.packageMarketplaceExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0;
|
||||
const es = require("event-stream");
|
||||
const fs = require("fs");
|
||||
const glob = require("glob");
|
||||
@@ -22,22 +22,28 @@ const fancyLog = require("fancy-log");
|
||||
const ansiColors = require("ansi-colors");
|
||||
const buffer = require('gulp-buffer');
|
||||
const json = require("gulp-json-editor");
|
||||
const jsoncParser = require("jsonc-parser");
|
||||
const webpack = require('webpack');
|
||||
const webpackGulp = require('webpack-stream');
|
||||
const util = require('./util');
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
const commit = util.getVersion(root);
|
||||
const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`;
|
||||
function minimizeLanguageJSON(input) {
|
||||
const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true });
|
||||
function minifyExtensionResources(input) {
|
||||
const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
|
||||
return input
|
||||
.pipe(tmLanguageJsonFilter)
|
||||
.pipe(jsonFilter)
|
||||
.pipe(buffer())
|
||||
.pipe(es.mapSync((f) => {
|
||||
f.contents = Buffer.from(JSON.stringify(JSON.parse(f.contents.toString('utf8'))));
|
||||
const errors = [];
|
||||
const value = jsoncParser.parse(f.contents.toString('utf8'), errors);
|
||||
if (errors.length === 0) {
|
||||
// file parsed OK => just stringify to drop whitespace and comments
|
||||
f.contents = Buffer.from(JSON.stringify(value));
|
||||
}
|
||||
return f;
|
||||
}))
|
||||
.pipe(tmLanguageJsonFilter.restore);
|
||||
.pipe(jsonFilter.restore);
|
||||
}
|
||||
function updateExtensionPackageJSON(input, update) {
|
||||
const packageJsonFilter = filter('extensions/*/package.json', { restore: true });
|
||||
@@ -57,24 +63,18 @@ function fromLocal(extensionPath, forWeb) {
|
||||
let input = isWebPacked
|
||||
? fromLocalWebpack(extensionPath, webpackConfigFileName)
|
||||
: fromLocalNormal(extensionPath);
|
||||
if (forWeb) {
|
||||
input = updateExtensionPackageJSON(input, (data) => {
|
||||
if (data.browser) {
|
||||
data.main = data.browser;
|
||||
}
|
||||
data.extensionKind = ['web'];
|
||||
return data;
|
||||
});
|
||||
}
|
||||
else if (isWebPacked) {
|
||||
if (isWebPacked) {
|
||||
input = updateExtensionPackageJSON(input, (data) => {
|
||||
delete data.scripts;
|
||||
delete data.dependencies;
|
||||
delete data.devDependencies;
|
||||
if (data.main) {
|
||||
data.main = data.main.replace('/out/', /dist/);
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
return minimizeLanguageJSON(input);
|
||||
return input;
|
||||
}
|
||||
function fromLocalWebpack(extensionPath, webpackConfigFileName) {
|
||||
const result = es.through();
|
||||
@@ -194,7 +194,6 @@ function fromMarketplace(extensionName, version, metadata) {
|
||||
exports.fromMarketplace = fromMarketplace;
|
||||
const excludedExtensions = [
|
||||
'vscode-api-tests',
|
||||
'vscode-web-playground',
|
||||
'vscode-colorize-tests',
|
||||
'vscode-test-resolver',
|
||||
'ms-vscode.node-debug',
|
||||
@@ -211,6 +210,7 @@ const externalExtensions = [
|
||||
'admin-tool-ext-win',
|
||||
'agent',
|
||||
'arc',
|
||||
'azdata',
|
||||
'import',
|
||||
'profiler',
|
||||
'admin-pack',
|
||||
@@ -222,105 +222,113 @@ const externalExtensions = [
|
||||
'sql-database-projects',
|
||||
'machine-learning',
|
||||
'sql-assessment',
|
||||
'asde-deployment'
|
||||
'asde-deployment',
|
||||
'sql-migration'
|
||||
];
|
||||
// extensions that require a rebuild since they have native parts
|
||||
const rebuildExtensions = [
|
||||
'big-data-cluster',
|
||||
'mssql'
|
||||
];
|
||||
const builtInExtensions = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions;
|
||||
function packageLocalExtensionsStream() {
|
||||
const localExtensionDescriptions = glob.sync('extensions/*/package.json')
|
||||
const marketplaceWebExtensions = [
|
||||
'ms-vscode.references-view'
|
||||
];
|
||||
const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8'));
|
||||
const builtInExtensions = productJson.builtInExtensions || [];
|
||||
const webBuiltInExtensions = productJson.webBuiltInExtensions || [];
|
||||
/**
|
||||
* Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts`
|
||||
*/
|
||||
function isWebExtension(manifest) {
|
||||
if (typeof manifest.extensionKind !== 'undefined') {
|
||||
const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind];
|
||||
return (extensionKind.indexOf('web') >= 0);
|
||||
}
|
||||
return (!Boolean(manifest.main) || Boolean(manifest.browser));
|
||||
}
|
||||
function packageLocalExtensionsStream(forWeb) {
|
||||
const localExtensionsDescriptions = (glob.sync('extensions/*/package.json')
|
||||
.map(manifestPath => {
|
||||
const absoluteManifestPath = path.join(root, manifestPath);
|
||||
const extensionPath = path.dirname(path.join(root, manifestPath));
|
||||
const extensionName = path.basename(extensionPath);
|
||||
return { name: extensionName, path: extensionPath };
|
||||
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
|
||||
})
|
||||
.filter(({ name }) => (name === 'vscode-web-playground' ? forWeb : true)) // package vscode-web-playground only for web
|
||||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
||||
.filter(({ name }) => externalExtensions.indexOf(name) === -1); // {{SQL CARBON EDIT}} Remove external Extensions with separate package
|
||||
const localExtensions = localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path, false)
|
||||
.filter(({ name }) => externalExtensions.indexOf(name) === -1) // {{SQL CARBON EDIT}} Remove external Extensions with separate package
|
||||
);
|
||||
const localExtensionsStream = minifyExtensionResources(es.merge(...localExtensionsDescriptions.map(extension => {
|
||||
return fromLocal(extension.path, forWeb)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
});
|
||||
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
|
||||
return es.merge(nodeModules, ...localExtensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
})));
|
||||
let result;
|
||||
if (forWeb) {
|
||||
result = localExtensionsStream;
|
||||
}
|
||||
else {
|
||||
// also include shared node modules
|
||||
result = es.merge(localExtensionsStream, gulp.src('extensions/node_modules/**', { base: '.' }));
|
||||
}
|
||||
return (result
|
||||
.pipe(util2.setExecutableBit(['**/*.sh'])));
|
||||
}
|
||||
exports.packageLocalExtensionsStream = packageLocalExtensionsStream;
|
||||
function packageLocalWebExtensionsStream() {
|
||||
const localExtensionDescriptions = glob.sync('extensions/*/package.json')
|
||||
.filter(manifestPath => {
|
||||
const packageJsonConfig = require(path.join(root, manifestPath));
|
||||
return !packageJsonConfig.main || packageJsonConfig.browser;
|
||||
})
|
||||
.map(manifestPath => {
|
||||
const extensionPath = path.dirname(path.join(root, manifestPath));
|
||||
const extensionName = path.basename(extensionPath);
|
||||
return { name: extensionName, path: extensionPath };
|
||||
});
|
||||
return es.merge(...localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path, true)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
}));
|
||||
}
|
||||
exports.packageLocalWebExtensionsStream = packageLocalWebExtensionsStream;
|
||||
function packageMarketplaceExtensionsStream() {
|
||||
const extensions = builtInExtensions.map(extension => {
|
||||
return fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
});
|
||||
return es.merge(extensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
}
|
||||
exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream;
|
||||
function packageMarketplaceWebExtensionsStream(builtInExtensions) {
|
||||
const extensions = builtInExtensions
|
||||
function packageMarketplaceExtensionsStream(forWeb) {
|
||||
const marketplaceExtensionsDescriptions = [
|
||||
...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)),
|
||||
...(forWeb ? webBuiltInExtensions : [])
|
||||
];
|
||||
const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions
|
||||
.map(extension => {
|
||||
const input = fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
return updateExtensionPackageJSON(input, (data) => {
|
||||
if (data.main) {
|
||||
data.browser = data.main;
|
||||
}
|
||||
data.extensionKind = ['web'];
|
||||
delete data.scripts;
|
||||
delete data.dependencies;
|
||||
delete data.devDependencies;
|
||||
return data;
|
||||
});
|
||||
});
|
||||
return es.merge(extensions);
|
||||
})));
|
||||
return (marketplaceExtensionsStream
|
||||
.pipe(util2.setExecutableBit(['**/*.sh'])));
|
||||
}
|
||||
exports.packageMarketplaceWebExtensionsStream = packageMarketplaceWebExtensionsStream;
|
||||
function scanBuiltinExtensions(extensionsRoot, forWeb) {
|
||||
exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream;
|
||||
function scanBuiltinExtensions(extensionsRoot, exclude = []) {
|
||||
const scannedExtensions = [];
|
||||
const extensionsFolders = fs.readdirSync(extensionsRoot);
|
||||
for (const extensionFolder of extensionsFolders) {
|
||||
const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json');
|
||||
if (!fs.existsSync(packageJSONPath)) {
|
||||
continue;
|
||||
try {
|
||||
const extensionsFolders = fs.readdirSync(extensionsRoot);
|
||||
for (const extensionFolder of extensionsFolders) {
|
||||
if (exclude.indexOf(extensionFolder) >= 0) {
|
||||
continue;
|
||||
}
|
||||
const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json');
|
||||
if (!fs.existsSync(packageJSONPath)) {
|
||||
continue;
|
||||
}
|
||||
let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8'));
|
||||
if (!isWebExtension(packageJSON)) {
|
||||
continue;
|
||||
}
|
||||
const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder));
|
||||
const packageNLSPath = children.filter(child => child === 'package.nls.json')[0];
|
||||
const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined;
|
||||
const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0];
|
||||
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
|
||||
scannedExtensions.push({
|
||||
extensionPath: extensionFolder,
|
||||
packageJSON,
|
||||
packageNLS,
|
||||
readmePath: readme ? path.join(extensionFolder, readme) : undefined,
|
||||
changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined,
|
||||
});
|
||||
}
|
||||
let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8'));
|
||||
const extensionKind = packageJSON['extensionKind'] || [];
|
||||
if (forWeb && extensionKind.indexOf('web') === -1) {
|
||||
continue;
|
||||
}
|
||||
const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder));
|
||||
const packageNLS = children.filter(child => child === 'package.nls.json')[0];
|
||||
const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0];
|
||||
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
|
||||
if (packageNLS) {
|
||||
// temporary
|
||||
packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS));
|
||||
}
|
||||
scannedExtensions.push({
|
||||
extensionPath: extensionFolder,
|
||||
packageJSON,
|
||||
packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined,
|
||||
readmePath: readme ? path.join(extensionFolder, readme) : undefined,
|
||||
changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined,
|
||||
});
|
||||
return scannedExtensions;
|
||||
}
|
||||
catch (ex) {
|
||||
return scannedExtensions;
|
||||
}
|
||||
return scannedExtensions;
|
||||
}
|
||||
exports.scanBuiltinExtensions = scanBuiltinExtensions;
|
||||
function packageExternalExtensionsStream() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import * as fancyLog from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
const buffer = require('gulp-buffer');
|
||||
import json = require('gulp-json-editor');
|
||||
import * as jsoncParser from 'jsonc-parser';
|
||||
const webpack = require('webpack');
|
||||
const webpackGulp = require('webpack-stream');
|
||||
const util = require('./util');
|
||||
@@ -28,16 +29,21 @@ const root = path.dirname(path.dirname(__dirname));
|
||||
const commit = util.getVersion(root);
|
||||
const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`;
|
||||
|
||||
function minimizeLanguageJSON(input: Stream): Stream {
|
||||
const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true });
|
||||
function minifyExtensionResources(input: Stream): Stream {
|
||||
const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
|
||||
return input
|
||||
.pipe(tmLanguageJsonFilter)
|
||||
.pipe(jsonFilter)
|
||||
.pipe(buffer())
|
||||
.pipe(es.mapSync((f: File) => {
|
||||
f.contents = Buffer.from(JSON.stringify(JSON.parse(f.contents.toString('utf8'))));
|
||||
const errors: jsoncParser.ParseError[] = [];
|
||||
const value = jsoncParser.parse(f.contents.toString('utf8'), errors);
|
||||
if (errors.length === 0) {
|
||||
// file parsed OK => just stringify to drop whitespace and comments
|
||||
f.contents = Buffer.from(JSON.stringify(value));
|
||||
}
|
||||
return f;
|
||||
}))
|
||||
.pipe(tmLanguageJsonFilter.restore);
|
||||
.pipe(jsonFilter.restore);
|
||||
}
|
||||
|
||||
function updateExtensionPackageJSON(input: Stream, update: (data: any) => any): Stream {
|
||||
@@ -61,16 +67,11 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream {
|
||||
? fromLocalWebpack(extensionPath, webpackConfigFileName)
|
||||
: fromLocalNormal(extensionPath);
|
||||
|
||||
if (forWeb) {
|
||||
input = updateExtensionPackageJSON(input, (data: any) => {
|
||||
if (data.browser) {
|
||||
data.main = data.browser;
|
||||
}
|
||||
data.extensionKind = ['web'];
|
||||
return data;
|
||||
});
|
||||
} else if (isWebPacked) {
|
||||
if (isWebPacked) {
|
||||
input = updateExtensionPackageJSON(input, (data: any) => {
|
||||
delete data.scripts;
|
||||
delete data.dependencies;
|
||||
delete data.devDependencies;
|
||||
if (data.main) {
|
||||
data.main = data.main.replace('/out/', /dist/);
|
||||
}
|
||||
@@ -78,7 +79,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream {
|
||||
});
|
||||
}
|
||||
|
||||
return minimizeLanguageJSON(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
@@ -224,10 +225,8 @@ export function fromMarketplace(extensionName: string, version: string, metadata
|
||||
.pipe(json({ __metadata: metadata }))
|
||||
.pipe(packageJsonFilter.restore);
|
||||
}
|
||||
|
||||
const excludedExtensions = [
|
||||
'vscode-api-tests',
|
||||
'vscode-web-playground',
|
||||
'vscode-colorize-tests',
|
||||
'vscode-test-resolver',
|
||||
'ms-vscode.node-debug',
|
||||
@@ -245,6 +244,7 @@ const externalExtensions = [
|
||||
'admin-tool-ext-win',
|
||||
'agent',
|
||||
'arc',
|
||||
'azdata',
|
||||
'import',
|
||||
'profiler',
|
||||
'admin-pack',
|
||||
@@ -256,7 +256,8 @@ const externalExtensions = [
|
||||
'sql-database-projects',
|
||||
'machine-learning',
|
||||
'sql-assessment',
|
||||
'asde-deployment'
|
||||
'asde-deployment',
|
||||
'sql-migration'
|
||||
];
|
||||
|
||||
// extensions that require a rebuild since they have native parts
|
||||
@@ -265,6 +266,10 @@ const rebuildExtensions = [
|
||||
'mssql'
|
||||
];
|
||||
|
||||
const marketplaceWebExtensions = [
|
||||
'ms-vscode.references-view'
|
||||
];
|
||||
|
||||
interface IBuiltInExtension {
|
||||
name: string;
|
||||
version: string;
|
||||
@@ -272,113 +277,134 @@ interface IBuiltInExtension {
|
||||
metadata: any;
|
||||
}
|
||||
|
||||
const builtInExtensions: IBuiltInExtension[] = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions;
|
||||
const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8'));
|
||||
const builtInExtensions: IBuiltInExtension[] = productJson.builtInExtensions || [];
|
||||
const webBuiltInExtensions: IBuiltInExtension[] = productJson.webBuiltInExtensions || [];
|
||||
|
||||
export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream {
|
||||
const localExtensionDescriptions = (<string[]>glob.sync('extensions/*/package.json'))
|
||||
.map(manifestPath => {
|
||||
const extensionPath = path.dirname(path.join(root, manifestPath));
|
||||
const extensionName = path.basename(extensionPath);
|
||||
return { name: extensionName, path: extensionPath };
|
||||
})
|
||||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
||||
.filter(({ name }) => externalExtensions.indexOf(name) === -1); // {{SQL CARBON EDIT}} Remove external Extensions with separate package
|
||||
|
||||
|
||||
const localExtensions = localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path, false)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
});
|
||||
|
||||
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
|
||||
return es.merge(nodeModules, ...localExtensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
type ExtensionKind = 'ui' | 'workspace' | 'web';
|
||||
interface IExtensionManifest {
|
||||
main: string;
|
||||
browser: string;
|
||||
extensionKind?: ExtensionKind | ExtensionKind[];
|
||||
}
|
||||
/**
|
||||
* Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts`
|
||||
*/
|
||||
function isWebExtension(manifest: IExtensionManifest): boolean {
|
||||
if (typeof manifest.extensionKind !== 'undefined') {
|
||||
const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind];
|
||||
return (extensionKind.indexOf('web') >= 0);
|
||||
}
|
||||
return (!Boolean(manifest.main) || Boolean(manifest.browser));
|
||||
}
|
||||
|
||||
export function packageLocalWebExtensionsStream(): NodeJS.ReadWriteStream {
|
||||
const localExtensionDescriptions = (<string[]>glob.sync('extensions/*/package.json'))
|
||||
.filter(manifestPath => {
|
||||
const packageJsonConfig = require(path.join(root, manifestPath));
|
||||
return !packageJsonConfig.main || packageJsonConfig.browser;
|
||||
})
|
||||
.map(manifestPath => {
|
||||
const extensionPath = path.dirname(path.join(root, manifestPath));
|
||||
const extensionName = path.basename(extensionPath);
|
||||
return { name: extensionName, path: extensionPath };
|
||||
});
|
||||
export function packageLocalExtensionsStream(forWeb: boolean): Stream {
|
||||
const localExtensionsDescriptions = (
|
||||
(<string[]>glob.sync('extensions/*/package.json'))
|
||||
.map(manifestPath => {
|
||||
const absoluteManifestPath = path.join(root, manifestPath);
|
||||
const extensionPath = path.dirname(path.join(root, manifestPath));
|
||||
const extensionName = path.basename(extensionPath);
|
||||
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
|
||||
})
|
||||
.filter(({ name }) => (name === 'vscode-web-playground' ? forWeb : true)) // package vscode-web-playground only for web
|
||||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
||||
.filter(({ name }) => externalExtensions.indexOf(name) === -1) // {{SQL CARBON EDIT}} Remove external Extensions with separate package
|
||||
);
|
||||
const localExtensionsStream = minifyExtensionResources(
|
||||
es.merge(
|
||||
...localExtensionsDescriptions.map(extension => {
|
||||
return fromLocal(extension.path, forWeb)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return es.merge(...localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path, true)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
}));
|
||||
let result: Stream;
|
||||
if (forWeb) {
|
||||
result = localExtensionsStream;
|
||||
} else {
|
||||
// also include shared node modules
|
||||
result = es.merge(localExtensionsStream, gulp.src('extensions/node_modules/**', { base: '.' }));
|
||||
}
|
||||
|
||||
return (
|
||||
result
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']))
|
||||
);
|
||||
}
|
||||
|
||||
export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream {
|
||||
const extensions = builtInExtensions.map(extension => {
|
||||
return fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
});
|
||||
export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream {
|
||||
const marketplaceExtensionsDescriptions = [
|
||||
...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)),
|
||||
...(forWeb ? webBuiltInExtensions : [])
|
||||
];
|
||||
const marketplaceExtensionsStream = minifyExtensionResources(
|
||||
es.merge(
|
||||
...marketplaceExtensionsDescriptions
|
||||
.map(extension => {
|
||||
const input = fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
return updateExtensionPackageJSON(input, (data: any) => {
|
||||
delete data.scripts;
|
||||
delete data.dependencies;
|
||||
delete data.devDependencies;
|
||||
return data;
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return es.merge(extensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
}
|
||||
|
||||
export function packageMarketplaceWebExtensionsStream(builtInExtensions: IBuiltInExtension[]): NodeJS.ReadWriteStream {
|
||||
const extensions = builtInExtensions
|
||||
.map(extension => {
|
||||
const input = fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
return updateExtensionPackageJSON(input, (data: any) => {
|
||||
if (data.main) {
|
||||
data.browser = data.main;
|
||||
}
|
||||
data.extensionKind = ['web'];
|
||||
return data;
|
||||
});
|
||||
});
|
||||
return es.merge(extensions);
|
||||
return (
|
||||
marketplaceExtensionsStream
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']))
|
||||
);
|
||||
}
|
||||
|
||||
export interface IScannedBuiltinExtension {
|
||||
extensionPath: string,
|
||||
packageJSON: any,
|
||||
packageNLSPath?: string,
|
||||
readmePath?: string,
|
||||
changelogPath?: string,
|
||||
extensionPath: string;
|
||||
packageJSON: any;
|
||||
packageNLS?: any;
|
||||
readmePath?: string;
|
||||
changelogPath?: string;
|
||||
}
|
||||
|
||||
export function scanBuiltinExtensions(extensionsRoot: string, forWeb: boolean): IScannedBuiltinExtension[] {
|
||||
export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] = []): IScannedBuiltinExtension[] {
|
||||
const scannedExtensions: IScannedBuiltinExtension[] = [];
|
||||
const extensionsFolders = fs.readdirSync(extensionsRoot);
|
||||
for (const extensionFolder of extensionsFolders) {
|
||||
const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json');
|
||||
if (!fs.existsSync(packageJSONPath)) {
|
||||
continue;
|
||||
}
|
||||
let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8'));
|
||||
const extensionKind: string[] = packageJSON['extensionKind'] || [];
|
||||
if (forWeb && extensionKind.indexOf('web') === -1) {
|
||||
continue;
|
||||
}
|
||||
const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder));
|
||||
const packageNLS = children.filter(child => child === 'package.nls.json')[0];
|
||||
const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0];
|
||||
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
|
||||
|
||||
if (packageNLS) {
|
||||
// temporary
|
||||
packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS));
|
||||
try {
|
||||
const extensionsFolders = fs.readdirSync(extensionsRoot);
|
||||
for (const extensionFolder of extensionsFolders) {
|
||||
if (exclude.indexOf(extensionFolder) >= 0) {
|
||||
continue;
|
||||
}
|
||||
const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json');
|
||||
if (!fs.existsSync(packageJSONPath)) {
|
||||
continue;
|
||||
}
|
||||
let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8'));
|
||||
if (!isWebExtension(packageJSON)) {
|
||||
continue;
|
||||
}
|
||||
const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder));
|
||||
const packageNLSPath = children.filter(child => child === 'package.nls.json')[0];
|
||||
const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined;
|
||||
const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0];
|
||||
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
|
||||
|
||||
scannedExtensions.push({
|
||||
extensionPath: extensionFolder,
|
||||
packageJSON,
|
||||
packageNLS,
|
||||
readmePath: readme ? path.join(extensionFolder, readme) : undefined,
|
||||
changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined,
|
||||
});
|
||||
}
|
||||
scannedExtensions.push({
|
||||
extensionPath: extensionFolder,
|
||||
packageJSON,
|
||||
packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined,
|
||||
readmePath: readme ? path.join(extensionFolder, readme) : undefined,
|
||||
changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined,
|
||||
});
|
||||
return scannedExtensions;
|
||||
} catch (ex) {
|
||||
return scannedExtensions;
|
||||
}
|
||||
return scannedExtensions;
|
||||
}
|
||||
|
||||
export function packageExternalExtensionsStream(): NodeJS.ReadWriteStream {
|
||||
|
||||
@@ -1147,12 +1147,7 @@ function createIslFile(originalFilePath, messages, language, innoSetup) {
|
||||
if (line.length > 0) {
|
||||
let firstChar = line.charAt(0);
|
||||
if (firstChar === '[' || firstChar === ';') {
|
||||
if (line === '; *** Inno Setup version 5.5.3+ English messages ***') {
|
||||
content.push(`; *** Inno Setup version 5.5.3+ ${innoSetup.defaultInfo.name} messages ***`);
|
||||
}
|
||||
else {
|
||||
content.push(line);
|
||||
}
|
||||
content.push(line);
|
||||
}
|
||||
else {
|
||||
let sections = line.split('=');
|
||||
|
||||
@@ -1316,11 +1316,7 @@ function createIslFile(originalFilePath: string, messages: Map<string>, language
|
||||
if (line.length > 0) {
|
||||
let firstChar = line.charAt(0);
|
||||
if (firstChar === '[' || firstChar === ';') {
|
||||
if (line === '; *** Inno Setup version 5.5.3+ English messages ***') {
|
||||
content.push(`; *** Inno Setup version 5.5.3+ ${innoSetup.defaultInfo!.name} messages ***`);
|
||||
} else {
|
||||
content.push(line);
|
||||
}
|
||||
content.push(line);
|
||||
} else {
|
||||
let sections: string[] = line.split('=');
|
||||
let key = sections[0];
|
||||
|
||||
@@ -28,14 +28,15 @@ const REPO_ROOT_PATH = path.join(__dirname, '../..');
|
||||
function log(prefix, message) {
|
||||
fancyLog(ansiColors.cyan('[' + prefix + ']'), message);
|
||||
}
|
||||
function loaderConfig(emptyPaths) {
|
||||
function loaderConfig() {
|
||||
const result = {
|
||||
paths: {
|
||||
'vs': 'out-build/vs',
|
||||
'sql': 'out-build/sql',
|
||||
'vscode': 'empty:'
|
||||
'vscode': 'empty:',
|
||||
'azdata': 'empty:' // {{SQL CARBON EDIT}}
|
||||
},
|
||||
nodeModules: emptyPaths || []
|
||||
amdModulesPattern: /^(vs|sql)\// // {{SQL CARBON EDIT}} include sql in regex
|
||||
};
|
||||
result['vs/css'] = { inlineResources: true };
|
||||
return result;
|
||||
@@ -71,7 +72,7 @@ function loader(src, bundledFileHeader, bundleLoader) {
|
||||
}))
|
||||
.pipe(concat('vs/loader.js')));
|
||||
}
|
||||
function toConcatStream(src, bundledFileHeader, sources, dest) {
|
||||
function toConcatStream(src, bundledFileHeader, sources, dest, fileContentMapper) {
|
||||
const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
|
||||
// If a bundle ends up including in any of the sources our copyright, then
|
||||
// insert a fake source at the beginning of each bundle with our copyright
|
||||
@@ -92,10 +93,12 @@ function toConcatStream(src, bundledFileHeader, sources, dest) {
|
||||
const treatedSources = sources.map(function (source) {
|
||||
const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
|
||||
const base = source.path ? root + `/${src}` : '';
|
||||
const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake';
|
||||
const contents = source.path ? fileContentMapper(source.contents, path) : source.contents;
|
||||
return new VinylFile({
|
||||
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
|
||||
path: path,
|
||||
base: base,
|
||||
contents: Buffer.from(source.contents)
|
||||
contents: Buffer.from(contents)
|
||||
});
|
||||
});
|
||||
return es.readArray(treatedSources)
|
||||
@@ -103,9 +106,9 @@ function toConcatStream(src, bundledFileHeader, sources, dest) {
|
||||
.pipe(concat(dest))
|
||||
.pipe(stats_1.createStatsStream(dest));
|
||||
}
|
||||
function toBundleStream(src, bundledFileHeader, bundles) {
|
||||
function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) {
|
||||
return es.merge(bundles.map(function (bundle) {
|
||||
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
|
||||
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper);
|
||||
}));
|
||||
}
|
||||
const DEFAULT_FILE_HEADER = [
|
||||
@@ -121,6 +124,7 @@ function optimizeTask(opts) {
|
||||
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
|
||||
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
|
||||
const out = opts.out;
|
||||
const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents);
|
||||
return function () {
|
||||
const bundlesStream = es.through(); // this stream will contain the bundled files
|
||||
const resourcesStream = es.through(); // this stream will contain the resources
|
||||
@@ -129,7 +133,7 @@ function optimizeTask(opts) {
|
||||
if (err || !result) {
|
||||
return bundlesStream.emit('error', JSON.stringify(err));
|
||||
}
|
||||
toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream);
|
||||
toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream);
|
||||
// Remove css inlined resources
|
||||
const filteredResources = resources.slice();
|
||||
result.cssInlinedResources.forEach(function (resource) {
|
||||
|
||||
@@ -18,7 +18,6 @@ import * as fancyLog from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
import * as path from 'path';
|
||||
import * as pump from 'pump';
|
||||
import * as sm from 'source-map';
|
||||
import * as terser from 'terser';
|
||||
import * as VinylFile from 'vinyl';
|
||||
import * as bundle from './bundle';
|
||||
@@ -32,14 +31,15 @@ function log(prefix: string, message: string): void {
|
||||
fancyLog(ansiColors.cyan('[' + prefix + ']'), message);
|
||||
}
|
||||
|
||||
export function loaderConfig(emptyPaths?: string[]) {
|
||||
export function loaderConfig() {
|
||||
const result: any = {
|
||||
paths: {
|
||||
'vs': 'out-build/vs',
|
||||
'sql': 'out-build/sql', // {{SQL CARBON EDIT}}
|
||||
'vscode': 'empty:'
|
||||
'vscode': 'empty:',
|
||||
'azdata': 'empty:' // {{SQL CARBON EDIT}}
|
||||
},
|
||||
nodeModules: emptyPaths || []
|
||||
amdModulesPattern: /^(vs|sql)\// // {{SQL CARBON EDIT}} include sql in regex
|
||||
};
|
||||
|
||||
result['vs/css'] = { inlineResources: true };
|
||||
@@ -49,10 +49,6 @@ export function loaderConfig(emptyPaths?: string[]) {
|
||||
|
||||
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
|
||||
|
||||
declare class FileSourceMap extends VinylFile {
|
||||
public sourceMap: sm.RawSourceMap;
|
||||
}
|
||||
|
||||
function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWriteStream {
|
||||
let sources = [
|
||||
`${src}/vs/loader.js`
|
||||
@@ -85,7 +81,7 @@ function loader(src: string, bundledFileHeader: string, bundleLoader: boolean):
|
||||
);
|
||||
}
|
||||
|
||||
function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string): NodeJS.ReadWriteStream {
|
||||
function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string, fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream {
|
||||
const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
|
||||
|
||||
// If a bundle ends up including in any of the sources our copyright, then
|
||||
@@ -109,11 +105,13 @@ function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.
|
||||
const treatedSources = sources.map(function (source) {
|
||||
const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
|
||||
const base = source.path ? root + `/${src}` : '';
|
||||
const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake';
|
||||
const contents = source.path ? fileContentMapper(source.contents, path) : source.contents;
|
||||
|
||||
return new VinylFile({
|
||||
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
|
||||
path: path,
|
||||
base: base,
|
||||
contents: Buffer.from(source.contents)
|
||||
contents: Buffer.from(contents)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,9 +121,9 @@ function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.
|
||||
.pipe(createStatsStream(dest));
|
||||
}
|
||||
|
||||
function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[]): NodeJS.ReadWriteStream {
|
||||
function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[], fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream {
|
||||
return es.merge(bundles.map(function (bundle) {
|
||||
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
|
||||
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -163,6 +161,12 @@ export interface IOptimizeTaskOpts {
|
||||
* (out folder name)
|
||||
*/
|
||||
languages?: Language[];
|
||||
/**
|
||||
* File contents interceptor
|
||||
* @param contents The contens of the file
|
||||
* @param path The absolute file path, always using `/`, even on Windows
|
||||
*/
|
||||
fileContentMapper?: (contents: string, path: string) => string;
|
||||
}
|
||||
|
||||
const DEFAULT_FILE_HEADER = [
|
||||
@@ -179,6 +183,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
|
||||
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
|
||||
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
|
||||
const out = opts.out;
|
||||
const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents);
|
||||
|
||||
return function () {
|
||||
const bundlesStream = es.through(); // this stream will contain the bundled files
|
||||
@@ -188,7 +193,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
|
||||
bundle.bundle(entryPoints, loaderConfig, function (err, result) {
|
||||
if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); }
|
||||
|
||||
toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream);
|
||||
toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream);
|
||||
|
||||
// Remove css inlined resources
|
||||
const filteredResources = resources.slice();
|
||||
|
||||
55
build/lib/preLaunch.js
Normal file
55
build/lib/preLaunch.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// @ts-check
|
||||
const path = require("path");
|
||||
const child_process_1 = require("child_process");
|
||||
const fs_1 = require("fs");
|
||||
const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn';
|
||||
const rootDir = path.resolve(__dirname, '..', '..');
|
||||
function runProcess(command, args = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = child_process_1.spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env });
|
||||
child.on('exit', err => !err ? resolve() : process.exit(err !== null && err !== void 0 ? err : 1));
|
||||
child.on('error', reject);
|
||||
});
|
||||
}
|
||||
async function exists(subdir) {
|
||||
try {
|
||||
await fs_1.promises.stat(path.join(rootDir, subdir));
|
||||
return true;
|
||||
}
|
||||
catch (_a) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async function ensureNodeModules() {
|
||||
if (!(await exists('node_modules'))) {
|
||||
await runProcess(yarn);
|
||||
}
|
||||
}
|
||||
async function getElectron() {
|
||||
await runProcess(yarn, ['electron']);
|
||||
}
|
||||
async function ensureCompiled() {
|
||||
if (!(await exists('out'))) {
|
||||
await runProcess(yarn, ['compile']);
|
||||
}
|
||||
}
|
||||
async function main() {
|
||||
await ensureNodeModules();
|
||||
await getElectron();
|
||||
await ensureCompiled();
|
||||
// Can't require this until after dependencies are installed
|
||||
const { getBuiltInExtensions } = require('./builtInExtensions');
|
||||
await getBuiltInExtensions();
|
||||
}
|
||||
if (require.main === module) {
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
65
build/lib/preLaunch.ts
Normal file
65
build/lib/preLaunch.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// @ts-check
|
||||
|
||||
import * as path from 'path';
|
||||
import { spawn } from 'child_process';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn';
|
||||
const rootDir = path.resolve(__dirname, '..', '..');
|
||||
|
||||
function runProcess(command: string, args: ReadonlyArray<string> = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env });
|
||||
child.on('exit', err => !err ? resolve() : process.exit(err ?? 1));
|
||||
child.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
async function exists(subdir: string) {
|
||||
try {
|
||||
await fs.stat(path.join(rootDir, subdir));
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureNodeModules() {
|
||||
if (!(await exists('node_modules'))) {
|
||||
await runProcess(yarn);
|
||||
}
|
||||
}
|
||||
|
||||
async function getElectron() {
|
||||
await runProcess(yarn, ['electron']);
|
||||
}
|
||||
|
||||
async function ensureCompiled() {
|
||||
if (!(await exists('out'))) {
|
||||
await runProcess(yarn, ['compile']);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await ensureNodeModules();
|
||||
await getElectron();
|
||||
await ensureCompiled();
|
||||
|
||||
// Can't require this until after dependencies are installed
|
||||
const { getBuiltInExtensions } = require('./builtInExtensions');
|
||||
await getBuiltInExtensions();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -33,7 +33,7 @@ function yarnInstall(location, opts) {
|
||||
|
||||
yarnInstall('extensions'); // node modules shared by all extensions
|
||||
|
||||
if (!(process.platform === 'win32' && process.env['npm_config_arch'] === 'arm64')) {
|
||||
if (!(process.platform === 'win32' && (process.arch === 'arm64' || process.env['npm_config_arch'] === 'arm64'))) {
|
||||
yarnInstall('remote'); // node modules used by vscode server
|
||||
yarnInstall('remote/web'); // node modules used by vscode web
|
||||
}
|
||||
@@ -73,3 +73,5 @@ yarnInstall('test/automation'); // node modules required for smoketest
|
||||
yarnInstall('test/smoke'); // node modules required for smoketest
|
||||
yarnInstall('test/integration/browser'); // node modules required for integration
|
||||
yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron
|
||||
|
||||
cp.execSync('git config pull.rebase true');
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"gulp-bom": "^1.0.0",
|
||||
"gulp-sourcemaps": "^1.11.0",
|
||||
"gulp-uglify": "^3.0.0",
|
||||
"iconv-lite-umd": "0.6.5",
|
||||
"iconv-lite-umd": "0.6.8",
|
||||
"jsonc-parser": "^2.3.0",
|
||||
"mime": "^1.3.4",
|
||||
"minimatch": "3.0.4",
|
||||
"minimist": "^1.2.3",
|
||||
@@ -49,7 +50,7 @@
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"terser": "4.3.8",
|
||||
"typescript": "^4.0.0-dev.20200629",
|
||||
"typescript": "^4.0.0-dev.20200803",
|
||||
"vsce": "1.48.0",
|
||||
"vscode-telemetry-extractor": "^1.6.0",
|
||||
"xml2js": "^0.4.17"
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"checkJs": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
"noUnusedParameters": true,
|
||||
"newLine": "lf"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
|
||||
@@ -34,6 +34,7 @@ VersionInfoVersion={#RawVersion}
|
||||
ShowLanguageDialog=auto
|
||||
ArchitecturesAllowed={#ArchitecturesAllowed}
|
||||
ArchitecturesInstallIn64BitMode={#ArchitecturesInstallIn64BitMode}
|
||||
WizardStyle=modern
|
||||
|
||||
#ifdef Sign
|
||||
SignTool=esrp
|
||||
@@ -47,7 +48,7 @@ DefaultDirName={pf}\{#DirName}
|
||||
#endif
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "{#RepoDir}\build\win32\i18n\Default.isl,{#RepoDir}\build\win32\i18n\messages.en.isl" {#LocalizedLanguageFile}
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl,{#RepoDir}\build\win32\i18n\messages.en.isl" {#LocalizedLanguageFile}
|
||||
Name: "german"; MessagesFile: "compiler:Languages\German.isl,{#RepoDir}\build\win32\i18n\messages.de.isl" {#LocalizedLanguageFile("deu")}
|
||||
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl,{#RepoDir}\build\win32\i18n\messages.es.isl" {#LocalizedLanguageFile("esp")}
|
||||
Name: "french"; MessagesFile: "compiler:Languages\French.isl,{#RepoDir}\build\win32\i18n\messages.fr.isl" {#LocalizedLanguageFile("fra")}
|
||||
@@ -58,7 +59,7 @@ Name: "korean"; MessagesFile: "{#RepoDir}\build\win32\i18n\Default.ko.isl,{#Repo
|
||||
Name: "simplifiedChinese"; MessagesFile: "{#RepoDir}\build\win32\i18n\Default.zh-cn.isl,{#RepoDir}\build\win32\i18n\messages.zh-cn.isl" {#LocalizedLanguageFile("chs")}
|
||||
Name: "traditionalChinese"; MessagesFile: "{#RepoDir}\build\win32\i18n\Default.zh-tw.isl,{#RepoDir}\build\win32\i18n\messages.zh-tw.isl" {#LocalizedLanguageFile("cht")}
|
||||
Name: "brazilianPortuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl,{#RepoDir}\build\win32\i18n\messages.pt-br.isl" {#LocalizedLanguageFile("ptb")}
|
||||
Name: "hungarian"; MessagesFile: "compiler:Languages\Hungarian.isl,{#RepoDir}\build\win32\i18n\messages.hu.isl" {#LocalizedLanguageFile("hun")}
|
||||
Name: "hungarian"; MessagesFile: "{#RepoDir}\build\win32\i18n\Default.hu.isl,{#RepoDir}\build\win32\i18n\messages.hu.isl" {#LocalizedLanguageFile("hun")}
|
||||
Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl,{#RepoDir}\build\win32\i18n\messages.tr.isl" {#LocalizedLanguageFile("trk")}
|
||||
|
||||
[InstallDelete]
|
||||
@@ -147,7 +148,7 @@ begin
|
||||
Result := True;
|
||||
|
||||
#if "user" == InstallTarget
|
||||
if not WizardSilent() and IsAdminLoggedOn() then begin
|
||||
if not WizardSilent() and IsAdmin() then begin
|
||||
if MsgBox('This User Installer is not meant to be run as an Administrator. If you would like to install Azure Data Studio for all users in this system, download the System Installer instead from https://docs.microsoft.com/sql/azure-data-studio/download. Are you sure you want to continue?', mbError, MB_OKCANCEL) = IDCANCEL then begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
366
build/win32/i18n/Default.hu.isl
Normal file
366
build/win32/i18n/Default.hu.isl
Normal file
@@ -0,0 +1,366 @@
|
||||
;Inno Setup version 6.0.3+ Hungarian messages
|
||||
;Based on the translation of Kornél Pál, kornelpal@gmail.com
|
||||
;István Szabó, E-mail: istvanszabo890629@gmail.com
|
||||
;
|
||||
; To download user-contributed translations of this file, go to:
|
||||
; http://www.jrsoftware.org/files/istrans/
|
||||
;
|
||||
; Note: When translating this text, do not add periods (.) to the end of
|
||||
; messages that didn't have them already, because on those messages Inno
|
||||
; Setup adds the periods automatically (appending a period would result in
|
||||
; two periods being displayed).
|
||||
|
||||
[LangOptions]
|
||||
; The following three entries are very important. Be sure to read and
|
||||
; understand the '[LangOptions] section' topic in the help file.
|
||||
LanguageName=Magyar
|
||||
LanguageID=$040E
|
||||
LanguageCodePage=1250
|
||||
; If the language you are translating to requires special font faces or
|
||||
; sizes, uncomment any of the following entries and change them accordingly.
|
||||
;DialogFontName=
|
||||
;DialogFontSize=8
|
||||
;WelcomeFontName=Verdana
|
||||
;WelcomeFontSize=12
|
||||
;TitleFontName=Arial CE
|
||||
;TitleFontSize=29
|
||||
;CopyrightFontName=Arial CE
|
||||
;CopyrightFontSize=8
|
||||
|
||||
[Messages]
|
||||
|
||||
; *** Application titles
|
||||
SetupAppTitle=Telepítő
|
||||
SetupWindowTitle=%1 - Telepítő
|
||||
UninstallAppTitle=Eltávolító
|
||||
UninstallAppFullTitle=%1 Eltávolító
|
||||
|
||||
; *** Misc. common
|
||||
InformationTitle=Információk
|
||||
ConfirmTitle=Megerősít
|
||||
ErrorTitle=Hiba
|
||||
|
||||
; *** SetupLdr messages
|
||||
SetupLdrStartupMessage=%1 telepítve lesz. Szeretné folytatni?
|
||||
LdrCannotCreateTemp=Átmeneti fájl létrehozása nem lehetséges. A telepítés megszakítva
|
||||
LdrCannotExecTemp=Fájl futtatása nem lehetséges az átmeneti könyvtárban. A telepítés megszakítva
|
||||
HelpTextNote=
|
||||
|
||||
; *** Startup error messages
|
||||
LastErrorMessage=%1.%n%nHiba %2: %3
|
||||
SetupFileMissing=A(z) %1 fájl hiányzik a telepítő könyvtárából. Kérem hárítsa el a problémát, vagy szerezzen be egy másik példányt a programból!
|
||||
SetupFileCorrupt=A telepítési fájlok sérültek. Kérem, szerezzen be új másolatot a programból!
|
||||
SetupFileCorruptOrWrongVer=A telepítési fájlok sérültek, vagy inkompatibilisek a telepítő ezen verziójával. Hárítsa el a problémát, vagy szerezzen be egy másik példányt a programból!
|
||||
InvalidParameter=A parancssorba átadott paraméter érvénytelen:%n%n%1
|
||||
SetupAlreadyRunning=A Telepítő már fut.
|
||||
WindowsVersionNotSupported=A program nem támogatja a Windows ezen verzióját.
|
||||
WindowsServicePackRequired=A program futtatásához %1 Service Pack %2 vagy újabb szükséges.
|
||||
NotOnThisPlatform=Ez a program nem futtatható %1 alatt.
|
||||
OnlyOnThisPlatform=Ezt a programot %1 alatt kell futtatni.
|
||||
OnlyOnTheseArchitectures=A program kizárólag a következő processzor architektúrákhoz tervezett Windows-on telepíthető:%n%n%1
|
||||
WinVersionTooLowError=A program futtatásához %1 %2 verziója vagy későbbi szükséges.
|
||||
WinVersionTooHighError=Ez a program nem telepíthető %1 %2 vagy későbbire.
|
||||
AdminPrivilegesRequired=Csak rendszergazdai módban telepíthető ez a program.
|
||||
PowerUserPrivilegesRequired=Csak rendszergazdaként vagy kiemelt felhasználóként telepíthető ez a program.
|
||||
SetupAppRunningError=A telepítő úgy észlelte %1 jelenleg fut.%n%nZárja be az összes példányt, majd kattintson az 'OK'-ra a folytatáshoz, vagy a 'Mégse'-re a kilépéshez.
|
||||
UninstallAppRunningError=Az eltávolító úgy észlelte %1 jelenleg fut.%n%nZárja be az összes példányt, majd kattintson az 'OK'-ra a folytatáshoz, vagy a 'Mégse'-re a kilépéshez.
|
||||
|
||||
; *** Startup questions
|
||||
PrivilegesRequiredOverrideTitle=Telepítési mód kiválasztása
|
||||
PrivilegesRequiredOverrideInstruction=Válasszon telepítési módot
|
||||
PrivilegesRequiredOverrideText1=%1 telepíthető az összes felhasználónak (rendszergazdai jogok szükségesek), vagy csak magának.
|
||||
PrivilegesRequiredOverrideText2=%1 csak magának telepíthető, vagy az összes felhasználónak (rendszergazdai jogok szükségesek).
|
||||
PrivilegesRequiredOverrideAllUsers=Telepítés &mindenkinek
|
||||
PrivilegesRequiredOverrideAllUsersRecommended=Telepítés &mindenkinek (ajánlott)
|
||||
PrivilegesRequiredOverrideCurrentUser=Telepítés csak &nekem
|
||||
PrivilegesRequiredOverrideCurrentUserRecommended=Telepítés csak &nekem (ajánlott)
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorCreatingDir=A Telepítő nem tudta létrehozni a(z) "%1" könyvtárat
|
||||
ErrorTooManyFilesInDir=Nem hozható létre fájl a(z) "%1" könyvtárban, mert az már túl sok fájlt tartalmaz
|
||||
|
||||
; *** Setup common messages
|
||||
ExitSetupTitle=Kilépés a telepítőből
|
||||
ExitSetupMessage=A telepítés még folyamatban van. Ha most kilép, a program nem kerül telepítésre.%n%nMásik alkalommal is futtatható a telepítés befejezéséhez%n%nKilép a telepítőből?
|
||||
AboutSetupMenuItem=&Névjegy...
|
||||
AboutSetupTitle=Telepítő névjegye
|
||||
AboutSetupMessage=%1 %2 verzió%n%3%n%nAz %1 honlapja:%n%4
|
||||
AboutSetupNote=
|
||||
TranslatorNote=
|
||||
|
||||
; *** Buttons
|
||||
ButtonBack=< &Vissza
|
||||
ButtonNext=&Tovább >
|
||||
ButtonInstall=&Telepít
|
||||
ButtonOK=OK
|
||||
ButtonCancel=Mégse
|
||||
ButtonYes=&Igen
|
||||
ButtonYesToAll=&Mindet
|
||||
ButtonNo=&Nem
|
||||
ButtonNoToAll=&Egyiket se
|
||||
ButtonFinish=&Befejezés
|
||||
ButtonBrowse=&Tallózás...
|
||||
ButtonWizardBrowse=T&allózás...
|
||||
ButtonNewFolder=Új &könyvtár
|
||||
|
||||
; *** "Select Language" dialog messages
|
||||
SelectLanguageTitle=Telepítő nyelvi beállítás
|
||||
SelectLanguageLabel=Válassza ki a telepítés alatt használt nyelvet.
|
||||
|
||||
; *** Common wizard text
|
||||
ClickNext=A folytatáshoz kattintson a 'Tovább'-ra, a kilépéshez a 'Mégse'-re.
|
||||
BeveledLabel=
|
||||
BrowseDialogTitle=Válasszon könyvtárt
|
||||
BrowseDialogLabel=Válasszon egy könyvtárat az alábbi listából, majd kattintson az 'OK'-ra.
|
||||
NewFolderName=Új könyvtár
|
||||
|
||||
; *** "Welcome" wizard page
|
||||
WelcomeLabel1=Üdvözli a(z) [name] Telepítővarázslója.
|
||||
WelcomeLabel2=A(z) [name/ver] telepítésre kerül a számítógépén.%n%nAjánlott minden, egyéb futó alkalmazás bezárása a folytatás előtt.
|
||||
|
||||
; *** "Password" wizard page
|
||||
WizardPassword=Jelszó
|
||||
PasswordLabel1=Ez a telepítés jelszóval védett.
|
||||
PasswordLabel3=Kérem adja meg a jelszót, majd kattintson a 'Tovább'-ra. A jelszavak kis- és nagy betű érzékenyek lehetnek.
|
||||
PasswordEditLabel=&Jelszó:
|
||||
IncorrectPassword=Az ön által megadott jelszó helytelen. Próbálja újra.
|
||||
|
||||
; *** "License Agreement" wizard page
|
||||
WizardLicense=Licencszerződés
|
||||
LicenseLabel=Olvassa el figyelmesen az információkat folytatás előtt.
|
||||
LicenseLabel3=Kérem, olvassa el az alábbi licencszerződést. A telepítés folytatásához, el kell fogadnia a szerződést.
|
||||
LicenseAccepted=&Elfogadom a szerződést
|
||||
LicenseNotAccepted=&Nem fogadom el a szerződést
|
||||
|
||||
; *** "Information" wizard pages
|
||||
WizardInfoBefore=Információk
|
||||
InfoBeforeLabel=Olvassa el a következő fontos információkat a folytatás előtt.
|
||||
InfoBeforeClickLabel=Ha készen áll, kattintson a 'Tovább'-ra.
|
||||
WizardInfoAfter=Információk
|
||||
InfoAfterLabel=Olvassa el a következő fontos információkat a folytatás előtt.
|
||||
InfoAfterClickLabel=Ha készen áll, kattintson a 'Tovább'-ra.
|
||||
|
||||
; *** "User Information" wizard page
|
||||
WizardUserInfo=Felhasználó adatai
|
||||
UserInfoDesc=Kérem, adja meg az adatait
|
||||
UserInfoName=&Felhasználónév:
|
||||
UserInfoOrg=&Szervezet:
|
||||
UserInfoSerial=&Sorozatszám:
|
||||
UserInfoNameRequired=Meg kell adnia egy nevet.
|
||||
|
||||
; *** "Select Destination Location" wizard page
|
||||
WizardSelectDir=Válasszon célkönyvtárat
|
||||
SelectDirDesc=Hova települjön a(z) [name]?
|
||||
SelectDirLabel3=A(z) [name] az alábbi könyvtárba lesz telepítve.
|
||||
SelectDirBrowseLabel=A folytatáshoz, kattintson a 'Tovább'-ra. Ha másik könyvtárat választana, kattintson a 'Tallózás'-ra.
|
||||
DiskSpaceGBLabel=At least [gb] GB szabad területre van szükség.
|
||||
DiskSpaceMBLabel=Legalább [mb] MB szabad területre van szükség.
|
||||
CannotInstallToNetworkDrive=A Telepítő nem tud hálózati meghajtóra telepíteni.
|
||||
CannotInstallToUNCPath=A Telepítő nem tud hálózati UNC elérési útra telepíteni.
|
||||
InvalidPath=Teljes útvonalat adjon meg, a meghajtó betűjelével; például:%n%nC:\Alkalmazás%n%nvagy egy hálózati útvonalat a következő alakban:%n%n\\kiszolgáló\megosztás
|
||||
InvalidDrive=A kiválasztott meghajtó vagy hálózati megosztás nem létezik vagy nem elérhető. Válasszon egy másikat.
|
||||
DiskSpaceWarningTitle=Nincs elég szabad terület
|
||||
DiskSpaceWarning=A Telepítőnek legalább %1 KB szabad lemezterületre van szüksége, viszont a kiválasztott meghajtón csupán %2 KB áll rendelkezésre.%n%nMindenképpen folytatja?
|
||||
DirNameTooLong=A könyvtár neve vagy az útvonal túl hosszú.
|
||||
InvalidDirName=A könyvtár neve érvénytelen.
|
||||
BadDirName32=A könyvtárak nevei ezen karakterek egyikét sem tartalmazhatják:%n%n%1
|
||||
DirExistsTitle=A könyvtár már létezik
|
||||
DirExists=A könyvtár:%n%n%1%n%nmár létezik. Mindenképp ide akar telepíteni?
|
||||
DirDoesntExistTitle=A könyvtár nem létezik
|
||||
DirDoesntExist=A könyvtár:%n%n%1%n%nnem létezik. Szeretné létrehozni?
|
||||
|
||||
; *** "Select Components" wizard page
|
||||
WizardSelectComponents=Összetevők kiválasztása
|
||||
SelectComponentsDesc=Mely összetevők kerüljenek telepítésre?
|
||||
SelectComponentsLabel2=Jelölje ki a telepítendő összetevőket; törölje a telepíteni nem kívánt összetevőket. Kattintson a 'Tovább'-ra, ha készen áll a folytatásra.
|
||||
FullInstallation=Teljes telepítés
|
||||
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||
CompactInstallation=Szokásos telepítés
|
||||
CustomInstallation=Egyéni telepítés
|
||||
NoUninstallWarningTitle=Létező összetevő
|
||||
NoUninstallWarning=A telepítő úgy találta, hogy a következő összetevők már telepítve vannak a számítógépre:%n%n%1%n%nEzen összetevők kijelölésének törlése, nem távolítja el azokat a számítógépről.%n%nMindenképpen folytatja?
|
||||
ComponentSize1=%1 KB
|
||||
ComponentSize2=%1 MB
|
||||
ComponentsDiskSpaceMBLabel=A jelenlegi kijelölés legalább [gb] GB lemezterületet igényel.
|
||||
ComponentsDiskSpaceMBLabel=A jelenlegi kijelölés legalább [mb] MB lemezterületet igényel.
|
||||
|
||||
; *** "Select Additional Tasks" wizard page
|
||||
WizardSelectTasks=További feladatok
|
||||
SelectTasksDesc=Mely kiegészítő feladatok kerüljenek végrehajtásra?
|
||||
SelectTasksLabel2=Jelölje ki, mely kiegészítő feladatokat hajtsa végre a Telepítő a(z) [name] telepítése során, majd kattintson a 'Tovább'-ra.
|
||||
|
||||
; *** "Select Start Menu Folder" wizard page
|
||||
WizardSelectProgramGroup=Start Menü könyvtára
|
||||
SelectStartMenuFolderDesc=Hova helyezze a Telepítő a program parancsikonjait?
|
||||
SelectStartMenuFolderLabel3=A Telepítő a program parancsikonjait a Start menü következő mappájában fogja létrehozni.
|
||||
SelectStartMenuFolderBrowseLabel=A folytatáshoz kattintson a 'Tovább'-ra. Ha másik mappát választana, kattintson a 'Tallózás'-ra.
|
||||
MustEnterGroupName=Meg kell adnia egy mappanevet.
|
||||
GroupNameTooLong=A könyvtár neve vagy az útvonal túl hosszú.
|
||||
InvalidGroupName=A könyvtár neve érvénytelen.
|
||||
BadGroupName=A könyvtárak nevei ezen karakterek egyikét sem tartalmazhatják:%n%n%1
|
||||
NoProgramGroupCheck2=&Ne hozzon létre mappát a Start menüben
|
||||
|
||||
; *** "Ready to Install" wizard page
|
||||
WizardReady=Készen állunk a telepítésre
|
||||
ReadyLabel1=A Telepítő készen áll, a(z) [name] számítógépre telepítéshez.
|
||||
ReadyLabel2a=Kattintson a 'Telepítés'-re a folytatáshoz, vagy a "Vissza"-ra a beállítások áttekintéséhez vagy megváltoztatásához.
|
||||
ReadyLabel2b=Kattintson a 'Telepítés'-re a folytatáshoz.
|
||||
ReadyMemoUserInfo=Felhasználó adatai:
|
||||
ReadyMemoDir=Telepítés célkönyvtára:
|
||||
ReadyMemoType=Telepítés típusa:
|
||||
ReadyMemoComponents=Választott összetevők:
|
||||
ReadyMemoGroup=Start menü mappája:
|
||||
ReadyMemoTasks=Kiegészítő feladatok:
|
||||
|
||||
; *** "Preparing to Install" wizard page
|
||||
WizardPreparing=Felkészülés a telepítésre
|
||||
PreparingDesc=A Telepítő felkészül a(z) [name] számítógépre történő telepítéshez.
|
||||
PreviousInstallNotCompleted=gy korábbi program telepítése/eltávolítása nem fejeződött be. Újra kell indítania a számítógépét a másik telepítés befejezéséhez.%n%nA számítógépe újraindítása után ismét futtassa a Telepítőt a(z) [name] telepítésének befejezéséhez.
|
||||
CannotContinue=A telepítés nem folytatható. A kilépéshez kattintson a 'Mégse'-re
|
||||
ApplicationsFound=A következő alkalmazások olyan fájlokat használnak, amelyeket a Telepítőnek frissíteni kell. Ajánlott, hogy engedélyezze a Telepítőnek ezen alkalmazások automatikus bezárását.
|
||||
ApplicationsFound2=A következő alkalmazások olyan fájlokat használnak, amelyeket a Telepítőnek frissíteni kell. Ajánlott, hogy engedélyezze a Telepítőnek ezen alkalmazások automatikus bezárását. A telepítés befejezése után a Telepítő megkísérli az alkalmazások újraindítását.
|
||||
CloseApplications=&Alkalmazások automatikus bezárása
|
||||
DontCloseApplications=&Ne zárja be az alkalmazásokat
|
||||
ErrorCloseApplications=A Telepítő nem tudott minden alkalmazást automatikusan bezárni. A folytatás előtt ajánlott minden, a Telepítő által frissítendő fájlokat használó alkalmazást bezárni.
|
||||
PrepareToInstallNeedsRestart=A telepítőnek újra kell indítania a számítógépet. Újraindítást követően, futtassa újból a telepítőt, a [name] telepítésének befejezéséhez .%n%nÚjra szeretné indítani most a számítógépet?
|
||||
|
||||
; *** "Installing" wizard page
|
||||
WizardInstalling=Telepítés
|
||||
InstallingLabel=Kérem várjon, amíg a(z) [name] telepítése zajlik.
|
||||
|
||||
; *** "Setup Completed" wizard page
|
||||
FinishedHeadingLabel=A(z) [name] telepítésének befejezése
|
||||
FinishedLabelNoIcons=A Telepítő végzett a(z) [name] telepítésével.
|
||||
FinishedLabel=A Telepítő végzett a(z) [name] telepítésével. Az alkalmazást a létrehozott ikonok kiválasztásával indíthatja.
|
||||
ClickFinish=Kattintson a 'Befejezés'-re a kilépéshez.
|
||||
FinishedRestartLabel=A(z) [name] telepítésének befejezéséhez újra kell indítani a számítógépet. Újraindítja most?
|
||||
FinishedRestartMessage=A(z) [name] telepítésének befejezéséhez, a Telepítőnek újra kell indítani a számítógépet.%n%nÚjraindítja most?
|
||||
ShowReadmeCheck=Igen, szeretném elolvasni a FONTOS fájlt
|
||||
YesRadio=&Igen, újraindítás most
|
||||
NoRadio=&Nem, később indítom újra
|
||||
; used for example as 'Run MyProg.exe'
|
||||
RunEntryExec=%1 futtatása
|
||||
; used for example as 'View Readme.txt'
|
||||
RunEntryShellExec=%1 megtekintése
|
||||
|
||||
; *** "Setup Needs the Next Disk" stuff
|
||||
ChangeDiskTitle=A Telepítőnek szüksége van a következő lemezre
|
||||
SelectDiskLabel2=Helyezze be a(z) %1. lemezt és kattintson az 'OK'-ra.%n%nHa a fájlok a lemez egy a megjelenítettől különböző mappájában találhatók, írja be a helyes útvonalat vagy kattintson a 'Tallózás'-ra.
|
||||
PathLabel=Ú&tvonal:
|
||||
FileNotInDir2=A(z) "%1" fájl nem található a következő helyen: "%2". Helyezze be a megfelelő lemezt vagy válasszon egy másik mappát.
|
||||
SelectDirectoryLabel=Adja meg a következő lemez helyét.
|
||||
|
||||
; *** Installation phase messages
|
||||
SetupAborted=A telepítés nem fejeződött be.%n%nHárítsa el a hibát és futtassa újból a Telepítőt.
|
||||
AbortRetryIgnoreSelectAction=Válasszon műveletet
|
||||
AbortRetryIgnoreRetry=&Újra
|
||||
AbortRetryIgnoreIgnore=&Hiba elvetése és folytatás
|
||||
AbortRetryIgnoreCancel=Telepítés megszakítása
|
||||
|
||||
; *** Installation status messages
|
||||
StatusClosingApplications=Alkalmazások bezárása...
|
||||
StatusCreateDirs=Könyvtárak létrehozása...
|
||||
StatusExtractFiles=Fájlok kibontása...
|
||||
StatusCreateIcons=Parancsikonok létrehozása...
|
||||
StatusCreateIniEntries=INI bejegyzések létrehozása...
|
||||
StatusCreateRegistryEntries=Rendszerleíró bejegyzések létrehozása...
|
||||
StatusRegisterFiles=Fájlok regisztrálása...
|
||||
StatusSavingUninstall=Eltávolító információk mentése...
|
||||
StatusRunProgram=Telepítés befejezése...
|
||||
StatusRestartingApplications=Alkalmazások újraindítása...
|
||||
StatusRollback=Változtatások visszavonása...
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorInternal2=Belső hiba: %1
|
||||
ErrorFunctionFailedNoCode=Sikertelen %1
|
||||
ErrorFunctionFailed=Sikertelen %1; kód: %2
|
||||
ErrorFunctionFailedWithMessage=Sikertelen %1; kód: %2.%n%3
|
||||
ErrorExecutingProgram=Nem hajtható végre a fájl:%n%1
|
||||
|
||||
; *** Registry errors
|
||||
ErrorRegOpenKey=Nem nyitható meg a rendszerleíró kulcs:%n%1\%2
|
||||
ErrorRegCreateKey=Nem hozható létre a rendszerleíró kulcs:%n%1\%2
|
||||
ErrorRegWriteKey=Nem módosítható a rendszerleíró kulcs:%n%1\%2
|
||||
|
||||
; *** INI errors
|
||||
ErrorIniEntry=Bejegyzés létrehozása sikertelen a következő INI fájlban: "%1".
|
||||
|
||||
; *** File copying errors
|
||||
FileAbortRetryIgnoreSkipNotRecommended=&Fájl kihagyása (nem ajánlott)
|
||||
FileAbortRetryIgnoreIgnoreNotRecommended=&Hiba elvetése és folytatás (nem ajánlott)
|
||||
SourceIsCorrupted=A forrásfájl megsérült
|
||||
SourceDoesntExist=A(z) "%1" forrásfájl nem létezik
|
||||
ExistingFileReadOnly2=A fájl csak olvashatóként van jelölve.
|
||||
ExistingFileReadOnlyRetry=Csak &olvasható tulajdonság eltávolítása és újra próbálkozás
|
||||
ExistingFileReadOnlyKeepExisting=&Létező fájl megtartása
|
||||
ErrorReadingExistingDest=Hiba lépett fel a fájl olvasása közben:
|
||||
FileExists=A fájl már létezik.%n%nFelül kívánja írni?
|
||||
ExistingFileNewer=A létező fájl újabb a telepítésre kerülőnél. Ajánlott a létező fájl megtartása.%n%nMeg kívánja tartani a létező fájlt?
|
||||
ErrorChangingAttr=Hiba lépett fel a fájl attribútumának módosítása közben:
|
||||
ErrorCreatingTemp=Hiba lépett fel a fájl telepítési könyvtárban történő létrehozása közben:
|
||||
ErrorReadingSource=Hiba lépett fel a forrásfájl olvasása közben:
|
||||
ErrorCopying=Hiba lépett fel a fájl másolása közben:
|
||||
ErrorReplacingExistingFile=Hiba lépett fel a létező fájl cseréje közben:
|
||||
ErrorRestartReplace=A fájl cseréje az újraindítás után sikertelen volt:
|
||||
ErrorRenamingTemp=Hiba lépett fel fájl telepítési könyvtárban történő átnevezése közben:
|
||||
ErrorRegisterServer=Nem lehet regisztrálni a DLL-t/OCX-et: %1
|
||||
ErrorRegSvr32Failed=Sikertelen RegSvr32. A visszaadott kód: %1
|
||||
ErrorRegisterTypeLib=Nem lehet regisztrálni a típustárat: %1
|
||||
|
||||
; *** Uninstall display name markings
|
||||
; used for example as 'My Program (32-bit)'
|
||||
UninstallDisplayNameMark=%1 (%2)
|
||||
; used for example as 'My Program (32-bit, All users)'
|
||||
UninstallDisplayNameMarks=%1 (%2, %3)
|
||||
UninstallDisplayNameMark32Bit=32-bit
|
||||
UninstallDisplayNameMark64Bit=64-bit
|
||||
UninstallDisplayNameMarkAllUsers=Minden felhasználó
|
||||
UninstallDisplayNameMarkCurrentUser=Jelenlegi felhasználó
|
||||
|
||||
; *** Post-installation errors
|
||||
ErrorOpeningReadme=Hiba lépett fel a FONTOS fájl megnyitása közben.
|
||||
ErrorRestartingComputer=A Telepítő nem tudta újraindítani a számítógépet. Indítsa újra kézileg.
|
||||
|
||||
; *** Uninstaller messages
|
||||
UninstallNotFound=A(z) "%1" fájl nem létezik. Nem távolítható el.
|
||||
UninstallOpenError=A(z) "%1" fájl nem nyitható meg. Nem távolítható el.
|
||||
UninstallUnsupportedVer=A(z) "%1" eltávolítási naplófájl formátumát nem tudja felismerni az eltávolító jelen verziója. Az eltávolítás nem folytatható
|
||||
UninstallUnknownEntry=Egy ismeretlen bejegyzés (%1) található az eltávolítási naplófájlban
|
||||
ConfirmUninstall=Biztosan el kívánja távolítani a(z) %1 programot és minden összetevőjét?
|
||||
UninstallOnlyOnWin64=Ezt a telepítést csak 64-bites Windowson lehet eltávolítani.
|
||||
OnlyAdminCanUninstall=Ezt a telepítést csak adminisztrációs jogokkal rendelkező felhasználó távolíthatja el.
|
||||
UninstallStatusLabel=Legyen türelemmel, amíg a(z) %1 számítógépéről történő eltávolítása befejeződik.
|
||||
UninstalledAll=A(z) %1 sikeresen el lett távolítva a számítógépről.
|
||||
UninstalledMost=A(z) %1 eltávolítása befejeződött.%n%nNéhány elemet nem lehetett eltávolítani. Törölje kézileg.
|
||||
UninstalledAndNeedsRestart=A(z) %1 eltávolításának befejezéséhez újra kell indítania a számítógépét.%n%nÚjraindítja most?
|
||||
UninstallDataCorrupted=A(z) "%1" fájl sérült. Nem távolítható el.
|
||||
|
||||
; *** Uninstallation phase messages
|
||||
ConfirmDeleteSharedFileTitle=Törli a megosztott fájlt?
|
||||
ConfirmDeleteSharedFile2=A rendszer azt jelzi, hogy a következő megosztott fájlra már nincs szüksége egyetlen programnak sem. Eltávolítja a megosztott fájlt?%n%nHa más programok még mindig használják a megosztott fájlt, akkor az eltávolítása után lehet, hogy nem fognak megfelelően működni. Ha bizonytalan, válassza a Nemet. A fájl megtartása nem okoz problémát a rendszerben.
|
||||
SharedFileNameLabel=Fájlnév:
|
||||
SharedFileLocationLabel=Helye:
|
||||
WizardUninstalling=Eltávolítás állapota
|
||||
StatusUninstalling=%1 eltávolítása...
|
||||
|
||||
; *** Shutdown block reasons
|
||||
ShutdownBlockReasonInstallingApp=%1 telepítése.
|
||||
ShutdownBlockReasonUninstallingApp=%1 eltávolítása.
|
||||
|
||||
; The custom messages below aren't used by Setup itself, but if you make
|
||||
; use of them in your scripts, you'll want to translate them.
|
||||
|
||||
[CustomMessages]
|
||||
|
||||
NameAndVersion=%1, verzió: %2
|
||||
AdditionalIcons=További parancsikonok:
|
||||
CreateDesktopIcon=&Asztali ikon létrehozása
|
||||
CreateQuickLaunchIcon=&Gyorsindító parancsikon létrehozása
|
||||
ProgramOnTheWeb=%1 az interneten
|
||||
UninstallProgram=Eltávolítás - %1
|
||||
LaunchProgram=Indítás %1
|
||||
AssocFileExtension=A(z) %1 &társítása a(z) %2 fájlkiterjesztéssel
|
||||
AssocingFileExtension=A(z) %1 társítása a(z) %2 fájlkiterjesztéssel...
|
||||
AutoStartProgramGroupDescription=Indítópult:
|
||||
AutoStartProgram=%1 automatikus indítása
|
||||
AddonHostProgramNotFound=A(z) %1 nem található a kiválasztott könyvtárban.%n%nMindenképpen folytatja?
|
||||
@@ -1,336 +0,0 @@
|
||||
; *** Inno Setup version 5.5.3+ English messages ***
|
||||
;
|
||||
; To download user-contributed translations of this file, go to:
|
||||
; http://www.jrsoftware.org/files/istrans/
|
||||
;
|
||||
; Note: When translating this text, do not add periods (.) to the end of
|
||||
; messages that didn't have them already, because on those messages Inno
|
||||
; Setup adds the periods automatically (appending a period would result in
|
||||
; two periods being displayed).
|
||||
|
||||
[LangOptions]
|
||||
; The following three entries are very important. Be sure to read and
|
||||
; understand the '[LangOptions] section' topic in the help file.
|
||||
LanguageName=English
|
||||
LanguageID=$0409
|
||||
LanguageCodePage=0
|
||||
; If the language you are translating to requires special font faces or
|
||||
; sizes, uncomment any of the following entries and change them accordingly.
|
||||
;DialogFontName=
|
||||
;DialogFontSize=8
|
||||
;WelcomeFontName=Verdana
|
||||
;WelcomeFontSize=12
|
||||
;TitleFontName=Arial
|
||||
;TitleFontSize=29
|
||||
;CopyrightFontName=Arial
|
||||
;CopyrightFontSize=8
|
||||
|
||||
[Messages]
|
||||
|
||||
; *** Application titles
|
||||
SetupAppTitle=Setup
|
||||
SetupWindowTitle=Setup - %1
|
||||
UninstallAppTitle=Uninstall
|
||||
UninstallAppFullTitle=%1 Uninstall
|
||||
|
||||
; *** Misc. common
|
||||
InformationTitle=Information
|
||||
ConfirmTitle=Confirm
|
||||
ErrorTitle=Error
|
||||
|
||||
; *** SetupLdr messages
|
||||
SetupLdrStartupMessage=This will install %1. Do you wish to continue?
|
||||
LdrCannotCreateTemp=Unable to create a temporary file. Setup aborted
|
||||
LdrCannotExecTemp=Unable to execute file in the temporary directory. Setup aborted
|
||||
|
||||
; *** Startup error messages
|
||||
LastErrorMessage=%1.%n%nError %2: %3
|
||||
SetupFileMissing=The file %1 is missing from the installation directory. Please correct the problem or obtain a new copy of the program.
|
||||
SetupFileCorrupt=The setup files are corrupted. Please obtain a new copy of the program.
|
||||
SetupFileCorruptOrWrongVer=The setup files are corrupted, or are incompatible with this version of Setup. Please correct the problem or obtain a new copy of the program.
|
||||
InvalidParameter=An invalid parameter was passed on the command line:%n%n%1
|
||||
SetupAlreadyRunning=Setup is already running.
|
||||
WindowsVersionNotSupported=This program does not support the version of Windows your computer is running.
|
||||
WindowsServicePackRequired=This program requires %1 Service Pack %2 or later.
|
||||
NotOnThisPlatform=This program will not run on %1.
|
||||
OnlyOnThisPlatform=This program must be run on %1.
|
||||
OnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1
|
||||
MissingWOW64APIs=The version of Windows you are running does not include functionality required by Setup to perform a 64-bit installation. To correct this problem, please install Service Pack %1.
|
||||
WinVersionTooLowError=This program requires %1 version %2 or later.
|
||||
WinVersionTooHighError=This program cannot be installed on %1 version %2 or later.
|
||||
AdminPrivilegesRequired=You must be logged in as an administrator when installing this program.
|
||||
PowerUserPrivilegesRequired=You must be logged in as an administrator or as a member of the Power Users group when installing this program.
|
||||
SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.
|
||||
UninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorCreatingDir=Setup was unable to create the directory "%1"
|
||||
ErrorTooManyFilesInDir=Unable to create a file in the directory "%1" because it contains too many files
|
||||
|
||||
; *** Setup common messages
|
||||
ExitSetupTitle=Exit Setup
|
||||
ExitSetupMessage=Setup is not complete. If you exit now, the program will not be installed.%n%nYou may run Setup again at another time to complete the installation.%n%nExit Setup?
|
||||
AboutSetupMenuItem=&About Setup...
|
||||
AboutSetupTitle=About Setup
|
||||
AboutSetupMessage=%1 version %2%n%3%n%n%1 home page:%n%4
|
||||
AboutSetupNote=
|
||||
TranslatorNote=
|
||||
|
||||
; *** Buttons
|
||||
ButtonBack=< &Back
|
||||
ButtonNext=&Next >
|
||||
ButtonInstall=&Install
|
||||
ButtonOK=OK
|
||||
ButtonCancel=Cancel
|
||||
ButtonYes=&Yes
|
||||
ButtonYesToAll=Yes to &All
|
||||
ButtonNo=&No
|
||||
ButtonNoToAll=N&o to All
|
||||
ButtonFinish=&Finish
|
||||
ButtonBrowse=&Browse...
|
||||
ButtonWizardBrowse=B&rowse...
|
||||
ButtonNewFolder=&Make New Folder
|
||||
|
||||
; *** "Select Language" dialog messages
|
||||
SelectLanguageTitle=Select Setup Language
|
||||
SelectLanguageLabel=Select the language to use during the installation:
|
||||
|
||||
; *** Common wizard text
|
||||
ClickNext=Click Next to continue, or Cancel to exit Setup.
|
||||
BeveledLabel=
|
||||
BrowseDialogTitle=Browse For Folder
|
||||
BrowseDialogLabel=Select a folder in the list below, then click OK.
|
||||
NewFolderName=New Folder
|
||||
|
||||
; *** "Welcome" wizard page
|
||||
WelcomeLabel1=Welcome to the [name] Setup Wizard
|
||||
WelcomeLabel2=This will install [name/ver] on your computer.%n%nIt is recommended that you close all other applications before continuing.
|
||||
|
||||
; *** "Password" wizard page
|
||||
WizardPassword=Password
|
||||
PasswordLabel1=This installation is password protected.
|
||||
PasswordLabel3=Please provide the password, then click Next to continue. Passwords are case-sensitive.
|
||||
PasswordEditLabel=&Password:
|
||||
IncorrectPassword=The password you entered is not correct. Please try again.
|
||||
|
||||
; *** "License Agreement" wizard page
|
||||
WizardLicense=License Agreement
|
||||
LicenseLabel=Please read the following important information before continuing.
|
||||
LicenseLabel3=Please read the following License Agreement. You must accept the terms of this agreement before continuing with the installation.
|
||||
LicenseAccepted=I &accept the agreement
|
||||
LicenseNotAccepted=I &do not accept the agreement
|
||||
|
||||
; *** "Information" wizard pages
|
||||
WizardInfoBefore=Information
|
||||
InfoBeforeLabel=Please read the following important information before continuing.
|
||||
InfoBeforeClickLabel=When you are ready to continue with Setup, click Next.
|
||||
WizardInfoAfter=Information
|
||||
InfoAfterLabel=Please read the following important information before continuing.
|
||||
InfoAfterClickLabel=When you are ready to continue with Setup, click Next.
|
||||
|
||||
; *** "User Information" wizard page
|
||||
WizardUserInfo=User Information
|
||||
UserInfoDesc=Please enter your information.
|
||||
UserInfoName=&User Name:
|
||||
UserInfoOrg=&Organization:
|
||||
UserInfoSerial=&Serial Number:
|
||||
UserInfoNameRequired=You must enter a name.
|
||||
|
||||
; *** "Select Destination Location" wizard page
|
||||
WizardSelectDir=Select Destination Location
|
||||
SelectDirDesc=Where should [name] be installed?
|
||||
SelectDirLabel3=Setup will install [name] into the following folder.
|
||||
SelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse.
|
||||
DiskSpaceMBLabel=At least [mb] MB of free disk space is required.
|
||||
CannotInstallToNetworkDrive=Setup cannot install to a network drive.
|
||||
CannotInstallToUNCPath=Setup cannot install to a UNC path.
|
||||
InvalidPath=You must enter a full path with drive letter; for example:%n%nC:\APP%n%nor a UNC path in the form:%n%n\\server\share
|
||||
InvalidDrive=The drive or UNC share you selected does not exist or is not accessible. Please select another.
|
||||
DiskSpaceWarningTitle=Not Enough Disk Space
|
||||
DiskSpaceWarning=Setup requires at least %1 KB of free space to install, but the selected drive only has %2 KB available.%n%nDo you want to continue anyway?
|
||||
DirNameTooLong=The folder name or path is too long.
|
||||
InvalidDirName=The folder name is not valid.
|
||||
BadDirName32=Folder names cannot include any of the following characters:%n%n%1
|
||||
DirExistsTitle=Folder Exists
|
||||
DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway?
|
||||
DirDoesntExistTitle=Folder Does Not Exist
|
||||
DirDoesntExist=The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be created?
|
||||
|
||||
; *** "Select Components" wizard page
|
||||
WizardSelectComponents=Select Components
|
||||
SelectComponentsDesc=Which components should be installed?
|
||||
SelectComponentsLabel2=Select the components you want to install; clear the components you do not want to install. Click Next when you are ready to continue.
|
||||
FullInstallation=Full installation
|
||||
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||
CompactInstallation=Compact installation
|
||||
CustomInstallation=Custom installation
|
||||
NoUninstallWarningTitle=Components Exist
|
||||
NoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway?
|
||||
ComponentSize1=%1 KB
|
||||
ComponentSize2=%1 MB
|
||||
ComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space.
|
||||
|
||||
; *** "Select Additional Tasks" wizard page
|
||||
WizardSelectTasks=Select Additional Tasks
|
||||
SelectTasksDesc=Which additional tasks should be performed?
|
||||
SelectTasksLabel2=Select the additional tasks you would like Setup to perform while installing [name], then click Next.
|
||||
|
||||
; *** "Select Start Menu Folder" wizard page
|
||||
WizardSelectProgramGroup=Select Start Menu Folder
|
||||
SelectStartMenuFolderDesc=Where should Setup place the program's shortcuts?
|
||||
SelectStartMenuFolderLabel3=Setup will create the program's shortcuts in the following Start Menu folder.
|
||||
SelectStartMenuFolderBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse.
|
||||
MustEnterGroupName=You must enter a folder name.
|
||||
GroupNameTooLong=The folder name or path is too long.
|
||||
InvalidGroupName=The folder name is not valid.
|
||||
BadGroupName=The folder name cannot include any of the following characters:%n%n%1
|
||||
NoProgramGroupCheck2=&Don't create a Start Menu folder
|
||||
|
||||
; *** "Ready to Install" wizard page
|
||||
WizardReady=Ready to Install
|
||||
ReadyLabel1=Setup is now ready to begin installing [name] on your computer.
|
||||
ReadyLabel2a=Click Install to continue with the installation, or click Back if you want to review or change any settings.
|
||||
ReadyLabel2b=Click Install to continue with the installation.
|
||||
ReadyMemoUserInfo=User information:
|
||||
ReadyMemoDir=Destination location:
|
||||
ReadyMemoType=Setup type:
|
||||
ReadyMemoComponents=Selected components:
|
||||
ReadyMemoGroup=Start Menu folder:
|
||||
ReadyMemoTasks=Additional tasks:
|
||||
|
||||
; *** "Preparing to Install" wizard page
|
||||
WizardPreparing=Preparing to Install
|
||||
PreparingDesc=Setup is preparing to install [name] on your computer.
|
||||
PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name].
|
||||
CannotContinue=Setup cannot continue. Please click Cancel to exit.
|
||||
ApplicationsFound=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications.
|
||||
ApplicationsFound2=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. After the installation has completed, Setup will attempt to restart the applications.
|
||||
CloseApplications=&Automatically close the applications
|
||||
DontCloseApplications=&Do not close the applications
|
||||
ErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing.
|
||||
|
||||
; *** "Installing" wizard page
|
||||
WizardInstalling=Installing
|
||||
InstallingLabel=Please wait while Setup installs [name] on your computer.
|
||||
|
||||
; *** "Setup Completed" wizard page
|
||||
FinishedHeadingLabel=Completing the [name] Setup Wizard
|
||||
FinishedLabelNoIcons=Setup has finished installing [name] on your computer.
|
||||
FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed icons.
|
||||
ClickFinish=Click Finish to exit Setup.
|
||||
FinishedRestartLabel=To complete the installation of [name], Setup must restart your computer. Would you like to restart now?
|
||||
FinishedRestartMessage=To complete the installation of [name], Setup must restart your computer.%n%nWould you like to restart now?
|
||||
ShowReadmeCheck=Yes, I would like to view the README file
|
||||
YesRadio=&Yes, restart the computer now
|
||||
NoRadio=&No, I will restart the computer later
|
||||
; used for example as 'Run MyProg.exe'
|
||||
RunEntryExec=Run %1
|
||||
; used for example as 'View Readme.txt'
|
||||
RunEntryShellExec=View %1
|
||||
|
||||
; *** "Setup Needs the Next Disk" stuff
|
||||
ChangeDiskTitle=Setup Needs the Next Disk
|
||||
SelectDiskLabel2=Please insert Disk %1 and click OK.%n%nIf the files on this disk can be found in a folder other than the one displayed below, enter the correct path or click Browse.
|
||||
PathLabel=&Path:
|
||||
FileNotInDir2=The file "%1" could not be located in "%2". Please insert the correct disk or select another folder.
|
||||
SelectDirectoryLabel=Please specify the location of the next disk.
|
||||
|
||||
; *** Installation phase messages
|
||||
SetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again.
|
||||
EntryAbortRetryIgnore=Click Retry to try again, Ignore to proceed anyway, or Abort to cancel installation.
|
||||
|
||||
; *** Installation status messages
|
||||
StatusClosingApplications=Closing applications...
|
||||
StatusCreateDirs=Creating directories...
|
||||
StatusExtractFiles=Extracting files...
|
||||
StatusCreateIcons=Creating shortcuts...
|
||||
StatusCreateIniEntries=Creating INI entries...
|
||||
StatusCreateRegistryEntries=Creating registry entries...
|
||||
StatusRegisterFiles=Registering files...
|
||||
StatusSavingUninstall=Saving uninstall information...
|
||||
StatusRunProgram=Finishing installation...
|
||||
StatusRestartingApplications=Restarting applications...
|
||||
StatusRollback=Rolling back changes...
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorInternal2=Internal error: %1
|
||||
ErrorFunctionFailedNoCode=%1 failed
|
||||
ErrorFunctionFailed=%1 failed; code %2
|
||||
ErrorFunctionFailedWithMessage=%1 failed; code %2.%n%3
|
||||
ErrorExecutingProgram=Unable to execute file:%n%1
|
||||
|
||||
; *** Registry errors
|
||||
ErrorRegOpenKey=Error opening registry key:%n%1\%2
|
||||
ErrorRegCreateKey=Error creating registry key:%n%1\%2
|
||||
ErrorRegWriteKey=Error writing to registry key:%n%1\%2
|
||||
|
||||
; *** INI errors
|
||||
ErrorIniEntry=Error creating INI entry in file "%1".
|
||||
|
||||
; *** File copying errors
|
||||
FileAbortRetryIgnore=Click Retry to try again, Ignore to skip this file (not recommended), or Abort to cancel installation.
|
||||
FileAbortRetryIgnore2=Click Retry to try again, Ignore to proceed anyway (not recommended), or Abort to cancel installation.
|
||||
SourceIsCorrupted=The source file is corrupted
|
||||
SourceDoesntExist=The source file "%1" does not exist
|
||||
ExistingFileReadOnly=The existing file is marked as read-only.%n%nClick Retry to remove the read-only attribute and try again, Ignore to skip this file, or Abort to cancel installation.
|
||||
ErrorReadingExistingDest=An error occurred while trying to read the existing file:
|
||||
FileExists=The file already exists.%n%nWould you like Setup to overwrite it?
|
||||
ExistingFileNewer=The existing file is newer than the one Setup is trying to install. It is recommended that you keep the existing file.%n%nDo you want to keep the existing file?
|
||||
ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file:
|
||||
ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory:
|
||||
ErrorReadingSource=An error occurred while trying to read the source file:
|
||||
ErrorCopying=An error occurred while trying to copy a file:
|
||||
ErrorReplacingExistingFile=An error occurred while trying to replace the existing file:
|
||||
ErrorRestartReplace=RestartReplace failed:
|
||||
ErrorRenamingTemp=An error occurred while trying to rename a file in the destination directory:
|
||||
ErrorRegisterServer=Unable to register the DLL/OCX: %1
|
||||
ErrorRegSvr32Failed=RegSvr32 failed with exit code %1
|
||||
ErrorRegisterTypeLib=Unable to register the type library: %1
|
||||
|
||||
; *** Post-installation errors
|
||||
ErrorOpeningReadme=An error occurred while trying to open the README file.
|
||||
ErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually.
|
||||
|
||||
; *** Uninstaller messages
|
||||
UninstallNotFound=File "%1" does not exist. Cannot uninstall.
|
||||
UninstallOpenError=File "%1" could not be opened. Cannot uninstall
|
||||
UninstallUnsupportedVer=The uninstall log file "%1" is in a format not recognized by this version of the uninstaller. Cannot uninstall
|
||||
UninstallUnknownEntry=An unknown entry (%1) was encountered in the uninstall log
|
||||
ConfirmUninstall=Are you sure you want to completely remove %1? Extensions and settings will not be removed.
|
||||
UninstallOnlyOnWin64=This installation can only be uninstalled on 64-bit Windows.
|
||||
OnlyAdminCanUninstall=This installation can only be uninstalled by a user with administrative privileges.
|
||||
UninstallStatusLabel=Please wait while %1 is removed from your computer.
|
||||
UninstalledAll=%1 was successfully removed from your computer.
|
||||
UninstalledMost=%1 uninstall complete.%n%nSome elements could not be removed. These can be removed manually.
|
||||
UninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now?
|
||||
UninstallDataCorrupted="%1" file is corrupted. Cannot uninstall
|
||||
|
||||
; *** Uninstallation phase messages
|
||||
ConfirmDeleteSharedFileTitle=Remove Shared File?
|
||||
ConfirmDeleteSharedFile2=The system indicates that the following shared file is no longer in use by any programs. Would you like for Uninstall to remove this shared file?%n%nIf any programs are still using this file and it is removed, those programs may not function properly. If you are unsure, choose No. Leaving the file on your system will not cause any harm.
|
||||
SharedFileNameLabel=File name:
|
||||
SharedFileLocationLabel=Location:
|
||||
WizardUninstalling=Uninstall Status
|
||||
StatusUninstalling=Uninstalling %1...
|
||||
|
||||
; *** Shutdown block reasons
|
||||
ShutdownBlockReasonInstallingApp=Installing %1.
|
||||
ShutdownBlockReasonUninstallingApp=Uninstalling %1.
|
||||
|
||||
; The custom messages below aren't used by Setup itself, but if you make
|
||||
; use of them in your scripts, you'll want to translate them.
|
||||
|
||||
[CustomMessages]
|
||||
|
||||
NameAndVersion=%1 version %2
|
||||
AdditionalIcons=Additional icons:
|
||||
CreateDesktopIcon=Create a &desktop icon
|
||||
CreateQuickLaunchIcon=Create a &Quick Launch icon
|
||||
ProgramOnTheWeb=%1 on the Web
|
||||
UninstallProgram=Uninstall %1
|
||||
LaunchProgram=Launch %1
|
||||
AssocFileExtension=&Associate %1 with the %2 file extension
|
||||
AssocingFileExtension=Associating %1 with the %2 file extension...
|
||||
AutoStartProgramGroupDescription=Startup:
|
||||
AutoStartProgram=Automatically start %1
|
||||
AddonHostProgramNotFound=%1 could not be located in the folder you selected.%n%nDo you want to continue anyway?
|
||||
@@ -1,12 +1,16 @@
|
||||
; *** Inno Setup version 5.5.3+ Korean messages ***
|
||||
;
|
||||
; To download user-contributed translations of this file, go to:
|
||||
; http://www.jrsoftware.org/files/istrans/
|
||||
; *** Inno Setup version 6.0.0+ Korean messages ***
|
||||
;
|
||||
; ▒ 6.0.3+ Translator: SungDong Kim (acroedit@gmail.com)
|
||||
; ▒ 5.5.3+ Translator: Domddol (domddol@gmail.com)
|
||||
; ▒ Translation date: MAR 04, 2014
|
||||
; ▒ Contributors: Hansoo KIM (iryna7@gmail.com), Woong-Jae An (a183393@hanmail.net)
|
||||
; ▒ Storage: http://www.jrsoftware.org/files/istrans/
|
||||
; ▒ 이 번역은 새로운 한국어 맞춤법 규칙을 준수합니다.
|
||||
; Note: When translating this text, do not add periods (.) to the end of
|
||||
; messages that didn't have them already, because on those messages Inno
|
||||
; Setup adds the periods automatically (appending a period would result in
|
||||
; two periods being displayed).
|
||||
|
||||
[LangOptions]
|
||||
; The following three entries are very important. Be sure to read and
|
||||
; understand the '[LangOptions] section' topic in the help file.
|
||||
@@ -23,50 +27,68 @@ LanguageCodePage=949
|
||||
;TitleFontSize=29
|
||||
;CopyrightFontName=Arial
|
||||
;CopyrightFontSize=8
|
||||
|
||||
[Messages]
|
||||
|
||||
; *** Application titles
|
||||
SetupAppTitle=설치
|
||||
SetupWindowTitle=설치 - %1
|
||||
SetupWindowTitle=%1 설치
|
||||
UninstallAppTitle=제거
|
||||
UninstallAppFullTitle=%1 제거
|
||||
|
||||
; *** Misc. common
|
||||
InformationTitle=정보
|
||||
ConfirmTitle=확인
|
||||
ErrorTitle=오류
|
||||
|
||||
; *** SetupLdr messages
|
||||
SetupLdrStartupMessage=그러면 %1이(가) 설치됩니다. 계속하시겠습니까?
|
||||
LdrCannotCreateTemp=임시 파일을 만들 수 없습니다. 설치 프로그램이 중단되었습니다.
|
||||
LdrCannotExecTemp=임시 디렉터리에서 파일을 실행할 수 없습니다. 설치 프로그램이 중단되었습니다.
|
||||
SetupLdrStartupMessage=%1을(를) 설치합니다, 계속하시겠습니까?
|
||||
LdrCannotCreateTemp=임시 파일을 만들 수 없습니다, 설치를 중단합니다
|
||||
LdrCannotExecTemp=임시 폴더의 파일을 실행할 수 없습니다, 설치를 중단합니다
|
||||
HelpTextNote=
|
||||
|
||||
; *** Startup error messages
|
||||
LastErrorMessage=%1.%n%n오류 %2: %3
|
||||
SetupFileMissing=파일 %1이(가) 설치 디렉터리에서 누락되었습니다. 문제를 해결하거나 프로그램을 새로 받으세요.
|
||||
SetupFileCorrupt=설치 파일이 손상되었습니다. 프로그램을 새로 받으세요.
|
||||
SetupFileCorruptOrWrongVer=설치 파일이 손상되었거나 이 버전의 설치 프로그램과 호환되지 않습니다. 문제를 해결하거나 프로그램을 새로 받으세요.
|
||||
InvalidParameter=명령줄에 잘못된 매개 변수가 전달됨:%n%n%1
|
||||
SetupAlreadyRunning=설치 프로그램이 이미 실행 중입니다.
|
||||
WindowsVersionNotSupported=이 프로그램은 컴퓨터에서 실행 중인 버전의 Windows를 지원하지 않습니다.
|
||||
WindowsServicePackRequired=이 프로그램을 설치하려면 %1 서비스 팩 %2 이상이 필요합니다.
|
||||
NotOnThisPlatform=이 프로그램은 %1에서 실행되지 않습니다.
|
||||
SetupFileMissing=%1 파일이 존재하지 않습니다, 문제를 해결해 보거나 새로운 설치 프로그램을 구하시기 바랍니다.
|
||||
SetupFileCorrupt=설치 파일이 손상되었습니다, 새로운 설치 프로그램을 구하시기 바랍니다.
|
||||
SetupFileCorruptOrWrongVer=설치 파일의 손상이거나 이 설치 버전과 호환되지 않습니다, 문제를 해결해 보거나 새로운 설치 프로그램을 구하시기 바랍니다.
|
||||
InvalidParameter=잘못된 매개 변수입니다:%n%n%1
|
||||
SetupAlreadyRunning=설치가 이미 실행 중입니다.
|
||||
WindowsVersionNotSupported=이 프로그램은 귀하의 Windows 버전을 지원하지 않습니다.
|
||||
WindowsServicePackRequired=이 프로그램을 실행하려면 %1 sp%2 이상이어야 합니다.
|
||||
NotOnThisPlatform=이 프로그램은 %1에서 작동하지 않습니다.
|
||||
OnlyOnThisPlatform=이 프로그램은 %1에서 실행해야 합니다.
|
||||
OnlyOnTheseArchitectures=이 프로그램은 프로세서 아키텍처 %n%n%1용으로 설계된 Windows 버전에서만 설치할 수 있습니다.
|
||||
MissingWOW64APIs=실행 중인 Windows 버전에는 설치 프로그램에서 64비트를 설치하는 데 필요한 기능이 없습니다. 이 문제를 해결하려면 서비스 팩 %1을(를) 설치하세요.
|
||||
WinVersionTooLowError=이 프로그램을 설치하려면 %1 버전 %2 이상이 필요합니다.
|
||||
WinVersionTooHighError=이 프로그램은 %1 버전 %2 이상에서는 설치할 수 없습니다.
|
||||
AdminPrivilegesRequired=이 프로그램을 설치할 때는 관리자로 로그인해야 합니다.
|
||||
PowerUserPrivilegesRequired=이 프로그램을 설치할 때는 관리자나 고급 사용자 그룹의 구성원으로 로그인해야 합니다.
|
||||
SetupAppRunningError=설치 프로그램에서 %1(이)가 현재 실행 중임을 감지했습니다.%n%n이 항목의 모든 인스턴스를 지금 닫고 계속하려면 [확인]을, 종료하려면 [취소]를 클릭하세요.
|
||||
UninstallAppRunningError=제거 작업에서 %1(이)가 현재 실행 중임을 감지했습니다.%n%n이 항목의 모든 인스턴스를 지금 닫고 계속하려면 [확인]을, 종료하려면 [취소]를 클릭하세요.
|
||||
OnlyOnTheseArchitectures=이 프로그램은 아래 처리 구조와 호환되는 Windows 버전에만 설치할 수 있습니다:%n%n%1
|
||||
WinVersionTooLowError=이 프로그램은 %1 버전 %2 이상이 필요합니다.
|
||||
WinVersionTooHighError=이 프로그램은 %1 버전 %2 이상에서 설치할 수 없습니다.
|
||||
AdminPrivilegesRequired=이 프로그램을 설치하려면 관리자로 로그인해야 합니다.
|
||||
PowerUserPrivilegesRequired=이 프로그램을 설치하려면 관리자 또는 고급 사용자로 로그인해야 합니다.
|
||||
SetupAppRunningError=현재 %1이(가) 실행 중입니다!%n%n지금 그것의 모든 인스턴스를 닫아 주십시오. 그런 다음 계속하려면 "확인"을, 종료하려면 "취소"를 클릭하십시오.
|
||||
UninstallAppRunningError=현재 %1이(가) 실행 중입니다!%n%n지금 그것의 모든 인스턴스를 닫아 주십시오. 그런 다음 계속하려면 "확인"을, 종료하려면 "취소"를 클릭하십시오.
|
||||
|
||||
; *** Startup questions
|
||||
PrivilegesRequiredOverrideTitle=설치 모드 선택
|
||||
PrivilegesRequiredOverrideInstruction=설치 모드를 선택해 주십시오
|
||||
PrivilegesRequiredOverrideText1=%1 은 모든 사용자(관리자 권한 필요) 또는 현재 사용자용으로 설치합니다.
|
||||
PrivilegesRequiredOverrideText2=%1 은 현재 사용자 또는 모든 사용자(관리자 권한 필요) 용으로 설치합니다.
|
||||
PrivilegesRequiredOverrideAllUsers=모든 사용자용으로 설치(&A)
|
||||
PrivilegesRequiredOverrideAllUsersRecommended=모든 사용자용으로 설치(&A) (추천)
|
||||
PrivilegesRequiredOverrideCurrentUser=현재 사용자용으로 설치(&M)
|
||||
PrivilegesRequiredOverrideCurrentUserRecommended=현재 사용자용으로 설치(&M) (추천)
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorCreatingDir=설치 프로그램에서 디렉터리 "%1"을(를) 만들 수 없습니다.
|
||||
ErrorTooManyFilesInDir=디렉터리 "%1"에 파일이 너무 많으므로 이 디렉터리에 파일을 만들 수 없습니다.
|
||||
ErrorCreatingDir="%1" 폴더를 만들 수 없습니다.
|
||||
ErrorTooManyFilesInDir="%1" 폴더에 파일이 너무 많기 때문에 파일을 만들 수 없습니다.
|
||||
|
||||
; *** Setup common messages
|
||||
ExitSetupTitle=설치 종료
|
||||
ExitSetupMessage=설치가 완료되지 않았습니다. 지금 종료하면 프로그램이 설치되지 않습니다.%n%n나중에 설치 프로그램을 다시 실행하여 설치를 끝낼 수 있습니다.%n%n설치 프로그램을 종료하시겠습니까?
|
||||
AboutSetupMenuItem=설치 프로그램 정보(&A)...
|
||||
AboutSetupTitle=설치 프로그램 정보
|
||||
AboutSetupMessage=%1 버전 %2%n%3%n%n%1 홈페이지:%n%4
|
||||
ExitSetupTitle=설치 완료
|
||||
ExitSetupMessage=설치가 완료되지 않았습니다, 여기서 설치를 종료하면 프로그램은 설치되지 않습니다.%n%n설치를 완료하려면 나중에 다시 설치 프로그램을 실행해야 합니다.%n%n그래도 설치를 종료하시겠습니까?
|
||||
AboutSetupMenuItem=설치 정보(&A)...
|
||||
AboutSetupTitle=설치 정보
|
||||
AboutSetupMessage=%1 버전 %2%n%3%n%n%1 홈 페이지:%n%4
|
||||
AboutSetupNote=
|
||||
TranslatorNote=
|
||||
|
||||
; *** Buttons
|
||||
ButtonBack=< 뒤로(&B)
|
||||
ButtonNext=다음(&N) >
|
||||
@@ -75,224 +97,271 @@ ButtonOK=Ȯ
|
||||
ButtonCancel=취소
|
||||
ButtonYes=예(&Y)
|
||||
ButtonYesToAll=모두 예(&A)
|
||||
ButtonNo=아니요(&N)
|
||||
ButtonNoToAll=모두 아니요(&O)
|
||||
ButtonFinish=마침(&F)
|
||||
ButtonNo=아니오(&N)
|
||||
ButtonNoToAll=모두 아니오(&O)
|
||||
ButtonFinish=종료(&F)
|
||||
ButtonBrowse=찾아보기(&B)...
|
||||
ButtonWizardBrowse=찾아보기(&R)
|
||||
ButtonWizardBrowse=찾아보기(&R)...
|
||||
ButtonNewFolder=새 폴더 만들기(&M)
|
||||
|
||||
; *** "Select Language" dialog messages
|
||||
SelectLanguageTitle=설치 언어 선택
|
||||
SelectLanguageLabel=설치 중에 사용할 언어를 선택하세요.
|
||||
SelectLanguageLabel=설치에 사용할 언어를 선택하십시오.
|
||||
|
||||
; *** Common wizard text
|
||||
ClickNext=계속하려면 [다음]을 클릭하고 설치 프로그램을 종료하려면 [취소]를 클릭하세요.
|
||||
ClickNext=계속하려면 "다음"을 클릭하고 설치를 종료하려면 "취소"를 클릭합니다.
|
||||
BeveledLabel=
|
||||
BrowseDialogTitle=폴더 찾아보기
|
||||
BrowseDialogLabel=아래 목록에서 폴더를 선택한 다음 [확인]을 클릭하세요.
|
||||
BrowseDialogLabel=아래 목록에서 폴더를 선택한 다음 "확인"을 클릭합니다.
|
||||
NewFolderName=새 폴더
|
||||
|
||||
; *** "Welcome" wizard page
|
||||
WelcomeLabel1=[name] 설치 마법사 시작
|
||||
WelcomeLabel2=이 마법사는 컴퓨터에 [name/ver]을(를) 설치합니다.%n%n계속하기 전에 다른 모든 응용 프로그램을 닫는 것이 좋습니다.
|
||||
WelcomeLabel2=이 마법사는 귀하의 컴퓨터에 [name/ver]을(를) 설치할 것입니다.%n%n설치하기 전에 다른 응용프로그램들을 모두 닫으시기 바랍니다.
|
||||
|
||||
; *** "Password" wizard page
|
||||
WizardPassword=암호
|
||||
PasswordLabel1=이 설치는 암호로 보호되고 있습니다.
|
||||
PasswordLabel3=계속하려면 암호를 입력한 다음 [다음]을 클릭하세요. 암호는 대소문자를 구분합니다.
|
||||
PasswordEditLabel=암호(&P):
|
||||
IncorrectPassword=입력한 암호가 잘못되었습니다. 다시 시도하세요.
|
||||
WizardPassword=비밀 번호
|
||||
PasswordLabel1=이 설치 마법사는 비밀 번호로 보호되어 있습니다.
|
||||
PasswordLabel3=비밀 번호를 입력하고 "다음"을 클릭하십시오. 비밀 번호는 대소문자를 구분해야 합니다.
|
||||
PasswordEditLabel=비밀 번호(&P):
|
||||
IncorrectPassword=비밀 번호가 정확하지 않습니다, 다시 입력하십시오.
|
||||
|
||||
; *** "License Agreement" wizard page
|
||||
WizardLicense=사용권 계약
|
||||
LicenseLabel=계속하기 전에 다음 중요한 정보를 읽어 보세요.
|
||||
LicenseLabel3=다음 사용권 계약을 읽어 주세요. 설치를 계속하려면 먼저 이 계약 조건에 동의해야 합니다.
|
||||
LicenseAccepted=계약에 동의함(&A)
|
||||
LicenseNotAccepted=계약에 동의 안 함(&D)
|
||||
LicenseLabel=계속하기 전에 다음의 중요 정보를 읽어보십시오.
|
||||
LicenseLabel3=다음 사용권 계약을 읽어보십시오, 설치를 계속하려면 이 계약에 동의해야 합니다.
|
||||
LicenseAccepted=동의합니다(&A)
|
||||
LicenseNotAccepted=동의하지 않습니다(&D)
|
||||
|
||||
; *** "Information" wizard pages
|
||||
WizardInfoBefore=정보
|
||||
InfoBeforeLabel=계속하기 전에 다음 중요한 정보를 읽어 보세요.
|
||||
InfoBeforeClickLabel=설치를 계속 진행할 준비가 되면 [다음]을 클릭합니다.
|
||||
InfoBeforeLabel=계속하기 전에 다음의 중요 정보를 읽어보십시오.
|
||||
InfoBeforeClickLabel=설치를 계속하려면 "다음"을 클릭하십시오.
|
||||
WizardInfoAfter=정보
|
||||
InfoAfterLabel=계속하기 전에 다음 중요한 정보를 읽어 보세요.
|
||||
InfoAfterClickLabel=설치를 계속 진행할 준비가 되면 [다음]을 클릭합니다.
|
||||
InfoAfterLabel=계속하기 전에 다음의 중요 정보를 읽어보십시오.
|
||||
InfoAfterClickLabel=설치를 계속하려면 "다음"을 클릭하십시오.
|
||||
|
||||
; *** "User Information" wizard page
|
||||
WizardUserInfo=사용자 정보
|
||||
UserInfoDesc=정보를 입력하세요.
|
||||
UserInfoDesc=사용자 정보를 입력하십시오.
|
||||
UserInfoName=사용자 이름(&U):
|
||||
UserInfoOrg=조직(&O):
|
||||
UserInfoSerial=일련 번호(&S):
|
||||
UserInfoNameRequired=이름을 입력해야 합니다.
|
||||
UserInfoSerial=시리얼 번호(&S):
|
||||
UserInfoNameRequired=사용자 이름을 입력하십시오.
|
||||
|
||||
; *** "Select Destination Location" wizard page
|
||||
WizardSelectDir=대상 위치 선택
|
||||
SelectDirDesc=[name]을(를) 어디에 설치하시겠습니까?
|
||||
SelectDirLabel3=설치 프로그램에서 [name]을(를) 다음 폴더에 설치합니다.
|
||||
SelectDirBrowseLabel=계속하려면 [다음]을 클릭하세요. 다른 폴더를 선택하려면 [찾아보기]를 클릭하세요.
|
||||
DiskSpaceMBLabel=적어도 [mb]MB의 여유 디스크 공간이 필요합니다.
|
||||
CannotInstallToNetworkDrive=설치 프로그램은 네트워크 드라이브에 설치할 수 없습니다.
|
||||
CannotInstallToUNCPath=설치 프로그램은 UNC 경로에 설치할 수 없습니다.
|
||||
InvalidPath=드라이브 문자와 함께 전체 경로를 입력해야 합니다. 예:%n%nC:\APP%n%n또는 다음 형태의 UNC 경로:%n%n\\server\share
|
||||
InvalidDrive=선택한 드라이브나 UNC 공유가 없거나 이 두 항목에 액세스할 수 없습니다. 다른 드라이브나 UNC 공유를 선택하세요.
|
||||
DiskSpaceWarningTitle=디스크 공간 부족
|
||||
DiskSpaceWarning=설치 프로그램을 설치하려면 여유 설치 공간이 적어도 %1KB가 필요하지만 선택한 드라이브의 가용 공간은 %2KB밖에 없습니다.%n%n그래도 계속하시겠습니까?
|
||||
WizardSelectDir=설치 위치 선택
|
||||
SelectDirDesc=[name]의 설치 위치를 선택하십시오.
|
||||
SelectDirLabel3=다음 폴더에 [name]을(를) 설치합니다.
|
||||
SelectDirBrowseLabel=계속하려면 "다음"을, 다른 폴더를 선택하려면 "찾아보기"를 클릭하십시오.
|
||||
DiskSpaceGBLabel=이 프로그램은 최소 [gb] GB의 디스크 여유 공간이 필요합니다.
|
||||
DiskSpaceMBLabel=이 프로그램은 최소 [mb] MB의 디스크 여유 공간이 필요합니다.
|
||||
CannotInstallToNetworkDrive=네트워크 드라이브에 설치할 수 없습니다.
|
||||
CannotInstallToUNCPath=UNC 경로에 설치할 수 없습니다.
|
||||
InvalidPath=드라이브 문자를 포함한 전체 경로를 입력하십시오.%n※ 예: C:\APP %n%n또는, UNC 형식의 경로를 입력하십시오.%n※ 예: \\server\share
|
||||
InvalidDrive=선택한 드라이브 또는 UNC 공유가 존재하지 않거나 액세스할 수 없습니다, 다른 경로를 선택하십시오.
|
||||
DiskSpaceWarningTitle=디스크 공간이 부족합니다
|
||||
DiskSpaceWarning=설치 시 최소 %1 KB 디스크 공간이 필요하지만, 선택한 드라이브의 여유 공간은 %2 KB 밖에 없습니다.%n%n그래도 계속하시겠습니까?
|
||||
DirNameTooLong=폴더 이름 또는 경로가 너무 깁니다.
|
||||
InvalidDirName=폴더 이름이 잘못되었습니다.
|
||||
BadDirName32=폴더 이름에는 %n%n%1 문자를 사용할 수 없습니다.
|
||||
DirExistsTitle=폴더 있음
|
||||
DirExists=폴더 %n%n%1%n%n이(가) 이미 있습니다. 그래도 해당 폴더에 설치하시겠습니까?
|
||||
DirDoesntExistTitle=폴더 없음
|
||||
DirDoesntExist=폴더 %n%n%1%n%n이(가) 없습니다. 폴더를 만드시겠습니까?
|
||||
InvalidDirName=폴더 이름이 유효하지 않습니다.
|
||||
BadDirName32=폴더 이름은 다음 문자를 포함할 수 없습니다:%n%n%1
|
||||
DirExistsTitle=폴더가 존재합니다
|
||||
DirExists=폴더 %n%n%1%n%n이(가) 이미 존재합니다, 이 폴더에 설치하시겠습니까?
|
||||
DirDoesntExistTitle=폴더가 존재하지 않습니다
|
||||
DirDoesntExist=폴더 %n%n%1%n%n이(가) 존재하지 않습니다, 새로 폴더를 만드시겠습니까?
|
||||
|
||||
; *** "Select Components" wizard page
|
||||
WizardSelectComponents=구성 요소 선택
|
||||
SelectComponentsDesc=어떤 구성 요소를 설치하시겠습니까?
|
||||
SelectComponentsLabel2=설치할 구성 요소는 선택하고 설치하지 않을 구성 요소는 지우세요. 계속 진행할 준비가 되면 [다음]을 클릭하세요.
|
||||
FullInstallation=전체 설치
|
||||
SelectComponentsDesc=설치할 구성 요소를 선택하십시오.
|
||||
SelectComponentsLabel2=필요한 구성 요소는 체크하고 불필요한 구성 요소는 체크 해제합니다, 계속하려면 "다음"을 클릭하십시오.
|
||||
FullInstallation=모두 설치
|
||||
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||
CompactInstallation=Compact 설치
|
||||
CompactInstallation=최소 설치
|
||||
CustomInstallation=사용자 지정 설치
|
||||
NoUninstallWarningTitle=구성 요소가 있음
|
||||
NoUninstallWarning=설치 프로그램에서 구성 요소 %n%n%1%n%n이(가) 컴퓨터에 이미 설치되어 있음을 감지했습니다. 이러한 구성 요소는 선택 취소해도 제거되지 않습니다.%n%n그래도 계속하시겠습니까?
|
||||
ComponentSize1=%1KB
|
||||
ComponentSize2=%1MB
|
||||
ComponentsDiskSpaceMBLabel=현재 선택을 위해서는 적어도 [mb]MB의 디스크 공간이 필요합니다.
|
||||
NoUninstallWarningTitle=구성 요소가 존재합니다
|
||||
NoUninstallWarning=다음 구성 요소가 이미 설치되어 있습니다:%n%n%1%n%n위 구성 요소을 선택하지 않으면, 프로그램 제거시 이 구성 요소들은 제거되지 않을 겁니다.%n%n그래도 계속하시겠습니까?
|
||||
ComponentSize1=%1 KB
|
||||
ComponentSize2=%1 MB
|
||||
ComponentsDiskSpaceGBLabel=현재 선택은 최소 [gb] GB의 디스크 여유 공간이 필요합니다.
|
||||
ComponentsDiskSpaceMBLabel=현재 선택은 최소 [mb] MB의 디스크 여유 공간이 필요합니다.
|
||||
|
||||
; *** "Select Additional Tasks" wizard page
|
||||
WizardSelectTasks=추가 작업 선택
|
||||
SelectTasksDesc=어떤 작업을 추가로 수행하시겠습니까?
|
||||
SelectTasksLabel2=설치 프로그램에서 [name]을(를) 설치하는 동안 수행할 추가 작업을 선택한 후 [다음]을 클릭하세요.
|
||||
SelectTasksDesc=수행할 추가 작업을 선택하십시오.
|
||||
SelectTasksLabel2=[name] 설치 과정에 포함할 추가 작업을 선택한 후, "다음"을 클릭하십시오.
|
||||
|
||||
; *** "Select Start Menu Folder" wizard page
|
||||
WizardSelectProgramGroup=시작 메뉴 폴더 선택
|
||||
SelectStartMenuFolderDesc=설치 프로그램에서 프로그램의 바로 가기를 어디에 만들도록 하시겠습니까?
|
||||
SelectStartMenuFolderLabel3=설치 프로그램에서 프로그램의 바로 가기를 다음 시작 메뉴 폴더에 만듭니다.
|
||||
SelectStartMenuFolderBrowseLabel=계속하려면 [다음]을 클릭하세요. 다른 폴더를 선택하려면 [찾아보기]를 클릭하세요.
|
||||
MustEnterGroupName=폴더 이름을 입력해야 합니다.
|
||||
SelectStartMenuFolderDesc=어디에 프로그램 바로가기를 위치하겠습니까?
|
||||
SelectStartMenuFolderLabel3=다음 시작 메뉴 폴더에 프로그램 바로가기를 만듭니다.
|
||||
SelectStartMenuFolderBrowseLabel=계속하려면 "다음"을 클릭하고, 다른 폴더를 선택하려면 "찾아보기"를 클릭하십시오.
|
||||
MustEnterGroupName=폴더 이름을 입력하십시오.
|
||||
GroupNameTooLong=폴더 이름 또는 경로가 너무 깁니다.
|
||||
InvalidGroupName=폴더 이름이 잘못되었습니다.
|
||||
BadGroupName=폴더 이름에는 %n%n%1 문자를 사용할 수 없습니다.
|
||||
InvalidGroupName=폴더 이름이 유효하지 않습니다.
|
||||
BadGroupName=폴더 이름은 다음 문자를 포함할 수 없습니다:%n%n%1
|
||||
NoProgramGroupCheck2=시작 메뉴 폴더를 만들지 않음(&D)
|
||||
|
||||
; *** "Ready to Install" wizard page
|
||||
WizardReady=설치 준비됨
|
||||
ReadyLabel1=이제 설치 프로그램이 컴퓨터에 [name] 설치를 시작할 준비가 되었습니다.
|
||||
ReadyLabel2a=설치를 계속하려면 [설치]를 클릭하고, 설정을 검토하거나 변경하려면 [뒤로]를 클릭하세요.
|
||||
ReadyLabel2b=설치를 계속하려면 [설치]를 클릭하세요.
|
||||
WizardReady=설치 준비 완료
|
||||
ReadyLabel1=귀하의 컴퓨터에 [name]을(를) 설치할 준비가 되었습니다.
|
||||
ReadyLabel2a=설치를 계속하려면 "설치"를, 설정을 변경하거나 검토하려면 "뒤로"를 클릭하십시오.
|
||||
ReadyLabel2b=설치를 계속하려면 "설치"를 클릭하십시오.
|
||||
ReadyMemoUserInfo=사용자 정보:
|
||||
ReadyMemoDir=대상 위치:
|
||||
ReadyMemoDir=설치 위치:
|
||||
ReadyMemoType=설치 유형:
|
||||
ReadyMemoComponents=선택한 구성 요소:
|
||||
ReadyMemoGroup=시작 메뉴 폴더:
|
||||
ReadyMemoTasks=추가 작업:
|
||||
|
||||
; *** "Preparing to Install" wizard page
|
||||
WizardPreparing=설치 준비 중
|
||||
PreparingDesc=설치 프로그램에서 컴퓨터에 [name] 설치를 준비하고 있습니다.
|
||||
PreviousInstallNotCompleted=이전 프로그램의 설치/제거 작업이 완료되지 않았습니다. 해당 설치를 완료하려면 컴퓨터를 다시 시작해야 합니다.%n%n컴퓨터를 다시 시작한 후 [name] 설치를 완료하려면 설치 프로그램을 다시 실행하세요.
|
||||
CannotContinue=설치 프로그램을 계속할 수 없습니다. 종료하려면 [취소]를 클릭하세요.
|
||||
ApplicationsFound=설치 프로그램에서 업데이트해야 하는 파일이 다음 응용 프로그램에 사용되고 있습니다. 설치 프로그램에서 이러한 응용 프로그램을 자동으로 닫도록 허용하는 것이 좋습니다.
|
||||
ApplicationsFound2=설치 프로그램에서 업데이트해야 하는 파일이 다음 응용 프로그램에 사용되고 있습니다. 설치 프로그램에서 이러한 응용 프로그램을 자동으로 닫도록 허용하는 것이 좋습니다. 설치가 완료되면 설치 프로그램에서 응용 프로그램을 다시 시작하려고 시도합니다.
|
||||
CloseApplications=응용 프로그램 자동 닫기(&A)
|
||||
DontCloseApplications=응용 프로그램을 닫지 않음(&D)
|
||||
ErrorCloseApplications=설치 프로그램에서 일부 응용 프로그램을 자동으로 닫을 수 없습니다. 계속하기 전에 설치 프로그램에서 업데이트해야 하는 파일을 사용하는 응용 프로그램을 모두 닫는 것이 좋습니다.
|
||||
PreparingDesc=귀하의 컴퓨터에 [name] 설치를 준비하는 중입니다.
|
||||
PreviousInstallNotCompleted=이전 프로그램의 설치/제거 작업이 완료되지 않았습니다, 완료하려면 컴퓨터를 다시 시작해야 합니다.%n%n컴퓨터를 다시 시작한 후, 설치 마법사를 다시 실행하여 [name] 설치를 완료하시기 바랍니다.
|
||||
CannotContinue=설치를 계속할 수 없습니다, "취소"를 클릭하여 설치를 종료하십시오.
|
||||
ApplicationsFound=다음 응용프로그램이 설치 업데이트가 필요한 파일을 사용하고 있습니다, 설치 마법사가 이런 응용프로그램을 자동으로 종료할 수 있도록 허용하시기 바랍니다.
|
||||
ApplicationsFound2=다음 응용프로그램이 설치 업데이트가 필요한 파일을 사용하고 있습니다, 설치 마법사가 이런 응용프로그램을 자동으로 종료할 수 있도록 허용하시기 바랍니다. 설치가 완료되면, 설치 마법사는 이 응용프로그램이 다시 시작되도록 시도할 겁니다.
|
||||
CloseApplications=자동으로 응용프로그램을 종료함(&A)
|
||||
DontCloseApplications=응용프로그램을 종료하지 않음(&D)
|
||||
ErrorCloseApplications=설치 마법사가 응용프로그램을 자동으로 종료할 수 없습니다, 계속하기 전에 설치 업데이트가 필요한 파일을 사용하고 있는 응용프로그램을 모두 종료하시기 바랍니다.
|
||||
PrepareToInstallNeedsRestart=설치 마법사는 귀하의 컴퓨터를 재시작해야 합니다. [name] 설치를 완료하기 위해 컴퓨터를 다시 시작한 후에 설치 마법사를 다시 실행해 주십시오.%n%n지금 다시 시작하시겠습니까?
|
||||
|
||||
; *** "Installing" wizard page
|
||||
WizardInstalling=설치 중
|
||||
InstallingLabel=설치 프로그램에서 컴퓨터에 [name]을(를) 설치하는 동안 기다려 주세요.
|
||||
InstallingLabel=귀하의 컴퓨터에 [name]을(를) 설치하는 중... 잠시 기다려 주십시오.
|
||||
|
||||
; *** "Setup Completed" wizard page
|
||||
FinishedHeadingLabel=[name] 설정 마법사를 완료하는 중
|
||||
FinishedLabelNoIcons=설치 프로그램에서 컴퓨터에 [name]을(를) 설치했습니다.
|
||||
FinishedLabel=설치 프로그램에서 컴퓨터에 [name]을(를) 설치했습니다. 설치한 바로 가기를 선택하여 해당 응용 프로그램을 시작할 수 있습니다.
|
||||
ClickFinish=설치 프로그램을 종료하려면 [마침]을 클릭하세요.
|
||||
FinishedRestartLabel=[name] 설치를 완료하려면 설치 프로그램에서 컴퓨터를 다시 시작해야 합니다. 지금 다시 시작하시겠습니까?
|
||||
FinishedRestartMessage=[name] 설치를 완료하려면 설치 프로그램에서 컴퓨터를 다시 시작해야 합니다.%n%n지금 다시 시작하시겠습니까?
|
||||
ShowReadmeCheck=예, README 파일을 보겠습니다.
|
||||
YesRadio=예, 컴퓨터를 지금 다시 시작하겠습니다(&Y).
|
||||
NoRadio=아니요, 컴퓨터를 나중에 다시 시작하겠습니다(&N).
|
||||
FinishedHeadingLabel=[name] 설치 마법사 완료
|
||||
FinishedLabelNoIcons=귀하의 컴퓨터에 [name]이(가) 설치되었습니다.
|
||||
FinishedLabel=귀하의 컴퓨터에 [name]이(가) 설치되었습니다, 응용프로그램은 설치된 아이콘을 선택하여 시작할 수 있습니다.
|
||||
ClickFinish=설치를 끝내려면 "종료"를 클릭하십시오.
|
||||
FinishedRestartLabel=[name] 설치를 완료하려면, 컴퓨터를 다시 시작해야 합니다. 지금 다시 시작하시겠습니까?
|
||||
FinishedRestartMessage=[name] 설치를 완료하려면, 컴퓨터를 다시 시작해야 합니다.%n%n지금 다시 시작하시겠습니까?
|
||||
ShowReadmeCheck=예, README 파일을 표시합니다
|
||||
YesRadio=예, 지금 다시 시작합니다(&Y)
|
||||
NoRadio=아니오, 나중에 다시 시작합니다(&N)
|
||||
; used for example as 'Run MyProg.exe'
|
||||
RunEntryExec=%1 실행
|
||||
; used for example as 'View Readme.txt'
|
||||
RunEntryShellExec=%1 보기
|
||||
RunEntryShellExec=%1 표시
|
||||
|
||||
; *** "Setup Needs the Next Disk" stuff
|
||||
ChangeDiskTitle=설치 프로그램에서 다음 디스크가 필요함
|
||||
SelectDiskLabel2=디스크 %1을(를) 삽입한 다음 [확인]을 클릭하세요.%n%n이 디스크의 파일이 아래 표시된 폴더가 아닌 다른 폴더에 있으면 올바른 경로를 입력하거나 [찾아보기]를 클릭하세요.
|
||||
ChangeDiskTitle=디스크가 필요합니다
|
||||
SelectDiskLabel2=디스크 %1을(를) 삽입하고 "확인"을 클릭하십시오.%n%n이 디스크 상의 파일이 아래 경로가 아닌 곳에 있는 경우, 올바른 경로를 입력하거나 "찾아보기"를 클릭하시기 바랍니다.
|
||||
PathLabel=경로(&P):
|
||||
FileNotInDir2="%2"에서 파일 "%1"을(를) 찾을 수 없습니다. 올바른 디스크를 삽입하거나 다른 폴더를 선택하세요.
|
||||
SelectDirectoryLabel=다음 디스크의 위치를 지정하세요.
|
||||
FileNotInDir2=%2에 파일 %1을(를) 위치할 수 없습니다, 올바른 디스크를 삽입하거나 다른 폴더를 선택하십시오.
|
||||
SelectDirectoryLabel=다음 디스크의 위치를 지정하십시오.
|
||||
|
||||
; *** Installation phase messages
|
||||
SetupAborted=설치를 완료하지 못했습니다.%n%n문제를 해결한 다음 설치 프로그램을 다시 실행하세요.
|
||||
EntryAbortRetryIgnore=다시 시도하려면 [다시 시도]를, 그래도 계속하려면 [무시]를, 설치를 취소하려면 [중단]을 클릭하세요.
|
||||
SetupAborted=설치가 완료되지 않았습니다.%n%n문제를 해결한 후, 다시 설치를 시작하십시오.
|
||||
AbortRetryIgnoreSelectAction=액션을 선택해 주십시오.
|
||||
AbortRetryIgnoreRetry=재시도(&T)
|
||||
AbortRetryIgnoreIgnore=오류를 무시하고 진행(&I)
|
||||
AbortRetryIgnoreCancel=설치 취소
|
||||
|
||||
; *** Installation status messages
|
||||
StatusClosingApplications=응용 프로그램을 닫는 중...
|
||||
StatusCreateDirs=디렉터리를 만드는 중...
|
||||
StatusClosingApplications=응용프로그램을 종료하는 중...
|
||||
StatusCreateDirs=폴더를 만드는 중...
|
||||
StatusExtractFiles=파일을 추출하는 중...
|
||||
StatusCreateIcons=바로 가기를 만드는 중...
|
||||
StatusCreateIcons=바로가기를 생성하는 중...
|
||||
StatusCreateIniEntries=INI 항목을 만드는 중...
|
||||
StatusCreateRegistryEntries=레지스트리 항목을 만드는 중...
|
||||
StatusRegisterFiles=파일을 등록하는 중...
|
||||
StatusSavingUninstall=제거 정보를 저장하는 중...
|
||||
StatusRunProgram=설치를 완료하는 중...
|
||||
StatusRestartingApplications=응용 프로그램을 다시 시작하는 중...
|
||||
StatusRollback=변경 사항을 롤백하는 중...
|
||||
StatusRestartingApplications=응용프로그램을 다시 시작하는 중...
|
||||
StatusRollback=변경을 취소하는 중...
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorInternal2=내부 오류: %1
|
||||
ErrorFunctionFailedNoCode=%1 실패
|
||||
ErrorFunctionFailed=%1 실패, 코드 %2
|
||||
ErrorFunctionFailedWithMessage=%1 실패, 코드 %2.%n%3
|
||||
ErrorExecutingProgram=파일을 실행할 수 없음:%n%1
|
||||
ErrorFunctionFailed=%1 실패; 코드 %2
|
||||
ErrorFunctionFailedWithMessage=%1 실패, 코드: %2.%n%3
|
||||
ErrorExecutingProgram=파일 실행 오류:%n%1
|
||||
|
||||
; *** Registry errors
|
||||
ErrorRegOpenKey=레지스트리 키를 여는 중 오류 발생:%n%1\%2
|
||||
ErrorRegCreateKey=레지스트리 키를 만드는 중 오류 발생:%n%1\%2
|
||||
ErrorRegWriteKey=레지스트리 키에 기록하는 중 오류 발생:%n%1\%2
|
||||
ErrorRegOpenKey=레지스트리 키 열기 오류:%n%1\%2
|
||||
ErrorRegCreateKey=레지스트리 키 생성 오류:%n%1\%2
|
||||
ErrorRegWriteKey=레지스트리 키 쓰기 오류:%n%1\%2
|
||||
|
||||
; *** INI errors
|
||||
ErrorIniEntry=파일 "%1"에 INI 항목을 만드는 중에 오류가 발생했습니다.
|
||||
ErrorIniEntry=%1 파일에 INI 항목 만들기 오류입니다.
|
||||
|
||||
; *** File copying errors
|
||||
FileAbortRetryIgnore=다시 시도하려면 [다시 시도]를, 이 파일을 건너뛰려면 [무시](권장되지 않음)를, 설치를 취소하려면 [중단]을 클릭하세요.
|
||||
FileAbortRetryIgnore2=다시 시도하려면 [다시 시도]를, 그래도 계속하려면 [무시](권장되지 않음)를, 설치를 취소하려면 [중단]을 클릭하세요.
|
||||
SourceIsCorrupted=원본 파일이 손상되었습니다.
|
||||
SourceDoesntExist=원본 파일 "%1"이(가) 없습니다.
|
||||
ExistingFileReadOnly=기존 파일이 읽기 전용으로 표시되어 있습니다.%n%n읽기 전용 특성을 제거하고 다시 시도하려면 [다시 시도]를, 이 파일을 건너뛰려면 [무시]를, 설치를 취소하려면 [중단]을 클릭하세요.
|
||||
ErrorReadingExistingDest=기존 파일을 읽는 중 오류 발생:
|
||||
FileExists=해당 파일이 이미 있습니다.%n%n설치 프로그램에서 이 파일을 덮어쓰도록 하시겠습니까?
|
||||
ExistingFileNewer=기존 파일이 설치 프로그램에서 설치하려는 파일보다 최신입니다. 기존 파일을 유지할 것을 권장합니다.%n%n기존 파일을 유지하시겠습니까?
|
||||
ErrorChangingAttr=기존 파일의 특성을 변경하는 중 오류 발생:
|
||||
ErrorCreatingTemp=대상 디렉터리에 파일을 만드는 중 오류 발생:
|
||||
ErrorReadingSource=원본 파일을 읽는 중 오류 발생:
|
||||
ErrorCopying=파일을 복사하는 중 오류 발생:
|
||||
ErrorReplacingExistingFile=기존 파일을 바꾸는 중 오류 발생:
|
||||
FileAbortRetryIgnoreSkipNotRecommended=이 파일을 건너띔(&S) (권장하지 않습니다)
|
||||
FileAbortRetryIgnoreIgnoreNotRecommended=오류를 무시하고 진행(&I) (권장하지 않습니다)
|
||||
SourceIsCorrupted=원본 파일이 손상됨
|
||||
SourceDoesntExist=원본 파일 %1이(가) 존재하지 않음
|
||||
ExistingFileReadOnly2=기존 파일은 읽기 전용이기때문에 대체할 수 없습니다.
|
||||
ExistingFileReadOnlyRetry=읽기 전용 속성을 해제하고 다시 시도하려면(&R)
|
||||
ExistingFileReadOnlyKeepExisting=기존 파일을 유지(&K)
|
||||
ErrorReadingExistingDest=기존 파일을 읽는 동안 오류 발생:
|
||||
FileExists=파일이 이미 존재합니다.%n%n파일을 덮어쓰시겠습니까?
|
||||
ExistingFileNewer=기존 파일이 설치하려고 하는 파일보다 새 파일입니다, 기존 파일을 유지하시기 바랍니다.%n%n기존 파일을 유지하시겠습니까?
|
||||
ErrorChangingAttr=기존 파일의 속성을 변경하는 동안 오류 발생:
|
||||
ErrorCreatingTemp=대상 폴더에 파일을 만드는 동안 오류 발생:
|
||||
ErrorReadingSource=원본 파일을 읽는 동안 오류 발생:
|
||||
ErrorCopying=파일을 복사하는 동안 오류 발생:
|
||||
ErrorReplacingExistingFile=기존 파일을 교체하는 동안 오류 발생:
|
||||
ErrorRestartReplace=RestartReplace 실패:
|
||||
ErrorRenamingTemp=대상 디렉터리에 있는 파일 이름을 바꾸는 중 오류 발생:
|
||||
ErrorRegisterServer=DLL/OCX를 등록할 수 없음: %1
|
||||
ErrorRegSvr32Failed=종료 코드 %1과(와) 함께 RegSvr32 실패
|
||||
ErrorRegisterTypeLib=형식 라이브러리를 등록할 수 없음: %1
|
||||
ErrorRenamingTemp=대상 폴더 내의 파일 이름을 바꾸는 동안 오류 발생:
|
||||
ErrorRegisterServer=DLL/OCX 등록 실패: %1
|
||||
ErrorRegSvr32Failed=RegSvr32가 다음 종료 코드로 실패: %1
|
||||
ErrorRegisterTypeLib=다음 유형의 라이브러리 등록에 실패: %1
|
||||
|
||||
; *** Uninstall display name markings
|
||||
; used for example as 'My Program (32-bit)'
|
||||
UninstallDisplayNameMark=%1 (%2)
|
||||
; used for example as 'My Program (32-bit, All users)'
|
||||
UninstallDisplayNameMarks=%1 (%2, %3)
|
||||
UninstallDisplayNameMark32Bit=32비트
|
||||
UninstallDisplayNameMark64Bit=64비트
|
||||
UninstallDisplayNameMarkAllUsers=모든 사용자
|
||||
UninstallDisplayNameMarkCurrentUser=현재 사용자
|
||||
|
||||
; *** Post-installation errors
|
||||
ErrorOpeningReadme=README 파일을 여는 중에 오류가 발생했습니다.
|
||||
ErrorRestartingComputer=설치 프로그램에서 컴퓨터를 다시 시작할 수 없습니다. 수동으로 진행하세요.
|
||||
ErrorOpeningReadme=README 파일을 여는 중 오류가 발생했습니다.
|
||||
ErrorRestartingComputer=컴퓨터를 다시 시작할 수 없습니다, 수동으로 다시 시작하십시오.
|
||||
|
||||
; *** Uninstaller messages
|
||||
UninstallNotFound=파일 "%1"이(가) 없습니다. 제거할 수 없습니다.
|
||||
UninstallOpenError=파일 "%1"을(를) 열 수 없습니다. 제거할 수 없습니다.
|
||||
UninstallUnsupportedVer=제거 로그 파일 "%1"이(가) 이 버전의 제거 프로그램에서 인식하지 못하는 형식입니다. 제거할 수 없습니다.
|
||||
UninstallUnknownEntry=제거 로그에서 알 수 없는 항목(%1)이 발견되었습니다.
|
||||
ConfirmUninstall=%1과(와) 해당 구성 요소를 모두 완전히 제거하시겠습니까?
|
||||
UninstallOnlyOnWin64=이 설치는 64비트 Windows에서만 제거할 수 있습니다.
|
||||
OnlyAdminCanUninstall=이 설치는 관리자 권한이 있는 사용자만 제거할 수 있습니다.
|
||||
UninstallStatusLabel=컴퓨터에서 %1을(를) 제거하는 동안 기다려 주세요.
|
||||
UninstalledAll=컴퓨터에서 %1을(를) 제거했습니다.
|
||||
UninstalledMost=%1 제거가 완료되었습니다.%n%n일부 요소는 제거할 수 없습니다. 이러한 항목은 수동으로 제거할 수 있습니다.
|
||||
UninstalledAndNeedsRestart=%1 제거를 완료하려면 컴퓨터를 다시 시작해야 합니다.%n%n지금 다시 시작하시겠습니까?
|
||||
UninstallDataCorrupted="%1" 파일이 손상되었습니다. 제거할 수 없습니다.
|
||||
UninstallNotFound=파일 %1이(가) 존재하지 않기 때문에, 제거를 실행할 수 없습니다.
|
||||
UninstallOpenError=파일 %1을(를) 열 수 없기 때문에, 제거를 실행할 수 없습니다.
|
||||
UninstallUnsupportedVer=삭제 로그 파일 "%1"은(는) 이 삭제 마법사로 인식할 수 없는 형식이기 때문에, 제거를 실행할 수 없습니다.
|
||||
UninstallUnknownEntry=알 수 없는 항목 %1이(가) 삭제 로그에 포함되어 있습니다.
|
||||
ConfirmUninstall=정말 %1와(과) 그 구성 요소를 모두 제거하시겠습니까?
|
||||
UninstallOnlyOnWin64=이 프로그램은 64비트 Windows에서만 제거할 수 있습니다.
|
||||
OnlyAdminCanUninstall=이 프로그램을 제거하려면 관리자 권한이 필요합니다.
|
||||
UninstallStatusLabel=귀하의 컴퓨터에서 %1을(를) 제거하는 중... 잠시 기다려 주십시오.
|
||||
UninstalledAll=%1이(가) 성공적으로 제거되었습니다!
|
||||
UninstalledMost=%1 제거가 완료되었습니다.%n%n일부 요소는 삭제할 수 없으니, 수동으로 제거하시기 바랍니다.
|
||||
UninstalledAndNeedsRestart=%1의 제거를 완료하려면, 컴퓨터를 다시 시작해야 합니다.%n%n지금 다시 시작하시겠습니까?
|
||||
UninstallDataCorrupted=파일 "%1"이(가) 손상되었기 때문에, 제거를 실행할 수 없습니다.
|
||||
|
||||
; *** Uninstallation phase messages
|
||||
ConfirmDeleteSharedFileTitle=공유 파일을 제거하시겠습니까?
|
||||
ConfirmDeleteSharedFile2=시스템에서는 이제 다음 공유 파일을 사용하는 프로그램이 없는 것으로 표시됩니다. 제거 작업을 통해 이 공유 파일을 제거하시겠습니까?%n%n아직 이 파일을 사용하는 프로그램이 있는데 이 파일을 제거하면 해당 프로그램이 올바르게 작동하지 않을 수 있습니다. 잘 모르는 경우 [아니요]를 선택하세요. 시스템에 파일을 그대로 두어도 아무런 문제가 발생하지 않습니다.
|
||||
ConfirmDeleteSharedFile2=시스템의 어떤 프로그램도 다음 공유 파일을 사용하지 않습니다, 이 공유 파일을 삭제하시겠습니까?%n%n이 파일을 다른 프로그램이 공유하고 있는 상태에서 이 파일을 제거할 경우, 해당 프로그램이 제대로 작동하지 않을 수 있으니, 확신이 없으면 "아니오"를 선택하셔도 됩니다. 시스템에 파일이 남아 있어도 문제가 되진 않습니다.
|
||||
SharedFileNameLabel=파일 이름:
|
||||
SharedFileLocationLabel=위치:
|
||||
WizardUninstalling=제거 상태
|
||||
StatusUninstalling=%1을(를) 제거하는 중...
|
||||
|
||||
; *** Shutdown block reasons
|
||||
ShutdownBlockReasonInstallingApp=%1을(를) 설치하는 중입니다.
|
||||
ShutdownBlockReasonUninstallingApp=%1을(를) 제거하는 중입니다.
|
||||
|
||||
; The custom messages below aren't used by Setup itself, but if you make
|
||||
; use of them in your scripts, you'll want to translate them.
|
||||
|
||||
[CustomMessages]
|
||||
|
||||
NameAndVersion=%1 버전 %2
|
||||
AdditionalIcons=추가 바로 가기:
|
||||
CreateDesktopIcon=바탕 화면 바로 가기 만들기(&D)
|
||||
CreateQuickLaunchIcon=빠른 실행 바로 가기 만들기(&Q)
|
||||
ProgramOnTheWeb=%1 웹 정보
|
||||
AdditionalIcons=아이콘 추가:
|
||||
CreateDesktopIcon=바탕 화면에 바로가기 만들기(&D)
|
||||
CreateQuickLaunchIcon=빠른 실행 아이콘 만들기(&Q)
|
||||
ProgramOnTheWeb=%1 웹페이지
|
||||
UninstallProgram=%1 제거
|
||||
LaunchProgram=%1 시작
|
||||
AssocFileExtension=%1을(를) %2 파일 확장명과 연결(&A)
|
||||
AssocingFileExtension=%1을(를) %2 파일 확장명과 연결 중...
|
||||
LaunchProgram=%1 실행
|
||||
AssocFileExtension=파일 확장자 %2을(를) %1에 연결합니다.
|
||||
AssocingFileExtension=파일 확장자 %2을(를) %1에 연결하는 중...
|
||||
AutoStartProgramGroupDescription=시작:
|
||||
AutoStartProgram=%1 자동 시작
|
||||
AddonHostProgramNotFound=선택한 폴더에서 %1을(를) 찾을 수 없습니다.%n%n그래도 계속하시겠습니까?
|
||||
AutoStartProgram=%1을(를) 자동으로 시작
|
||||
AddonHostProgramNotFound=%1은(는) 선택한 폴더에 위치할 수 없습니다.%n%n그래도 계속하시겠습니까?
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
; *** Inno Setup version 5.5.3+ Simplified Chinese messages ***
|
||||
; *** Inno Setup version 6.0.3+ Chinese Simplified messages ***
|
||||
;
|
||||
; To download user-contributed translations of this file, go to:
|
||||
; http://www.jrsoftware.org/files/istrans/
|
||||
; Maintained by Zhenghan Yang
|
||||
; Email: 847320916@QQ.com
|
||||
; Translation based on network resource
|
||||
; The latest Translation is on https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
|
||||
;
|
||||
; Note: When translating this text, do not add periods (.) to the end of
|
||||
; messages that didn't have them already, because on those messages Inno
|
||||
; Setup adds the periods automatically (appending a period would result in
|
||||
; two periods being displayed).
|
||||
|
||||
[LangOptions]
|
||||
; The following three entries are very important. Be sure to read and
|
||||
; understand the '[LangOptions] section' topic in the help file.
|
||||
LanguageName=Simplified Chinese
|
||||
LanguageName=简体中文
|
||||
; If Language Name display incorrect, uncomment next line
|
||||
; LanguageName=<7B80><4F53><4E2D><6587>
|
||||
LanguageID=$0804
|
||||
LanguageCodePage=936
|
||||
; If the language you are translating to requires special font faces or
|
||||
@@ -23,276 +24,342 @@ LanguageCodePage=936
|
||||
;TitleFontSize=29
|
||||
;CopyrightFontName=Arial
|
||||
;CopyrightFontSize=8
|
||||
|
||||
[Messages]
|
||||
; *** Application titles
|
||||
SetupAppTitle=安装程序
|
||||
SetupWindowTitle=安装程序 - %1
|
||||
UninstallAppTitle=卸载
|
||||
UninstallAppFullTitle=%1 卸载
|
||||
|
||||
; *** 应用程序标题
|
||||
SetupAppTitle=安装
|
||||
SetupWindowTitle=安装 - %1
|
||||
UninstallAppTitle=卸载
|
||||
UninstallAppFullTitle=%1 卸载
|
||||
|
||||
; *** Misc. common
|
||||
InformationTitle=信息
|
||||
ConfirmTitle=确认
|
||||
ErrorTitle=错误
|
||||
InformationTitle=信息
|
||||
ConfirmTitle=确认
|
||||
ErrorTitle=错误
|
||||
|
||||
; *** SetupLdr messages
|
||||
SetupLdrStartupMessage=这将安装 %1。是否要继续?
|
||||
LdrCannotCreateTemp=无法创建临时文件。安装程序已中止
|
||||
LdrCannotExecTemp=无法在临时目录中执行文件。安装程序已中止
|
||||
; *** Startup error messages
|
||||
LastErrorMessage=%1。%n%n错误 %2: %3
|
||||
SetupFileMissing=安装目录缺失文件 %1。请更正该问题或获取该问题的新副本。
|
||||
SetupFileCorrupt=安装程序文件夹已损坏。请获取该程序的新副本。
|
||||
SetupFileCorruptOrWrongVer=安装程序文件夹已损坏或与此安装程序版本不兼容。请更正该问题或获取该程序的新副本。
|
||||
InvalidParameter=命令行 %n%n%1 上传递了一个无效参数
|
||||
SetupAlreadyRunning=安装程序已在运行。
|
||||
WindowsVersionNotSupported=此程序不支持你计算机正运行的 Windows 版本。
|
||||
WindowsServicePackRequired=此程序需要 %1 服务包 %2 或更高版本。
|
||||
NotOnThisPlatform=此程序将不在 %1 上运行。
|
||||
OnlyOnThisPlatform=此程序必须在 %1 上运行。
|
||||
OnlyOnTheseArchitectures=此程序仅可安装在为以下处理器体系结构设计的 Windows 版本上:%n%n%1
|
||||
MissingWOW64APIs=你正运行的 Windows 版本不包含安装程序执行 64 位安装所需的功能。要更正此问题,请安装服务包 %1。
|
||||
WinVersionTooLowError=此程序需要 %1 版本 %2 或更高版本。
|
||||
WinVersionTooHighError=此程序不能安装在 %1 版本 %2 或更高的版本上。
|
||||
AdminPrivilegesRequired=在安装此程序时必须作为管理员登录。
|
||||
PowerUserPrivilegesRequired=安装此程序时必须以管理员或 Power User 组成员身份登录。
|
||||
SetupAppRunningError=安装程序检测到 %1 当前正在运行。%n%n请立即关闭它的所有实例,然后单击“确定”以继续,或单击“取消”以退出。
|
||||
UninstallAppRunningError=卸载检测到 %1 当前正在运行。%n%n请立即关闭它的所有实例,然后单击“确定”以继续或单击“取消”以退出。
|
||||
; *** Misc. errors
|
||||
ErrorCreatingDir=安装程序无法创建目录“%1”
|
||||
ErrorTooManyFilesInDir=无法在目录“%1”中创建文件,因为它包含太多文件
|
||||
; *** Setup common messages
|
||||
ExitSetupTitle=退出安装程序
|
||||
ExitSetupMessage=安装程序未完成。如果立即退出,将不会安装该程序。%n%n可在其他时间再次运行安装程序以完成安装。%n%n是否退出安装程序?
|
||||
AboutSetupMenuItem=关于安装程序(&A)...
|
||||
AboutSetupTitle=关于安装程序
|
||||
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4
|
||||
SetupLdrStartupMessage=现在将安装 %1。您想要继续吗?
|
||||
LdrCannotCreateTemp=不能创建临时文件。安装中断。
|
||||
LdrCannotExecTemp=不能执行临时目录中的文件。安装中断。
|
||||
HelpTextNote=
|
||||
|
||||
; *** 启动错误消息
|
||||
LastErrorMessage=%1.%n%n错误 %2: %3
|
||||
SetupFileMissing=安装目录中的文件 %1 丢失。请修正这个问题或获取一个新的程序副本。
|
||||
SetupFileCorrupt=安装文件已损坏。请获取一个新的程序副本。
|
||||
SetupFileCorruptOrWrongVer=安装文件已损坏,或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。
|
||||
InvalidParameter=无效的命令行参数: %n%n%1
|
||||
SetupAlreadyRunning=安装程序正在运行。
|
||||
WindowsVersionNotSupported=这个程序不支持该版本的计算机运行。
|
||||
WindowsServicePackRequired=这个程序要求%1服务包%1或更高。
|
||||
NotOnThisPlatform=这个程序将不能运行于 %1。
|
||||
OnlyOnThisPlatform=这个程序必须运行于 %1。
|
||||
OnlyOnTheseArchitectures=这个程序只能在为下列处理器结构设计的 Windows 版本中进行安装:%n%n%1
|
||||
WinVersionTooLowError=这个程序需要 %1 版本 %2 或更高。
|
||||
WinVersionTooHighError=这个程序不能安装于 %1 版本 %2 或更高。
|
||||
AdminPrivilegesRequired=在安装这个程序时您必须以管理员身份登录。
|
||||
PowerUserPrivilegesRequired=在安装这个程序时您必须以管理员身份或有权限的用户组身份登录。
|
||||
SetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后单击“确定”继续,或按“取消”退出。
|
||||
UninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后单击“确定”继续,或按“取消”退出。
|
||||
|
||||
; *** 启动问题
|
||||
PrivilegesRequiredOverrideTitle=选择安装程序模式
|
||||
PrivilegesRequiredOverrideInstruction=选择安装模式
|
||||
PrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限),或仅为您安装。
|
||||
PrivilegesRequiredOverrideText2=%1 只能为您安装,或为所有用户安装(需要管理员权限)。
|
||||
PrivilegesRequiredOverrideAllUsers=为所有用户安装(&A)
|
||||
PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(建议选项)(&A)
|
||||
PrivilegesRequiredOverrideCurrentUser=只为我安装(&M)
|
||||
PrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(建议选项)(&M)
|
||||
|
||||
; *** 其它错误
|
||||
ErrorCreatingDir=安装程序不能创建目录“%1”。
|
||||
ErrorTooManyFilesInDir=不能在目录“%1”中创建文件,因为里面的文件太多
|
||||
|
||||
; *** 安装程序公共消息
|
||||
ExitSetupTitle=退出安装程序
|
||||
ExitSetupMessage=安装程序未完成安装。如果您现在退出,您的程序将不能安装。%n%n您可以以后再运行安装程序完成安装。%n%n退出安装程序吗?
|
||||
AboutSetupMenuItem=关于安装程序(&A)...
|
||||
AboutSetupTitle=关于安装程序
|
||||
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4
|
||||
AboutSetupNote=
|
||||
TranslatorNote=
|
||||
; *** Buttons
|
||||
ButtonBack=< 上一步(&B)
|
||||
ButtonNext=下一步(&N) >
|
||||
ButtonInstall=安装(&I)
|
||||
ButtonOK=确定
|
||||
ButtonCancel=取消
|
||||
ButtonYes=是(&Y)
|
||||
ButtonYesToAll=接受全部(&A)
|
||||
ButtonNo=否(&N)
|
||||
ButtonNoToAll=否定全部(&O)
|
||||
ButtonFinish=完成(&F)
|
||||
ButtonBrowse=浏览(&B)...
|
||||
ButtonWizardBrowse=浏览(&R)...
|
||||
ButtonNewFolder=新建文件夹(&M)
|
||||
; *** "Select Language" dialog messages
|
||||
SelectLanguageTitle=选择安装程序语言
|
||||
SelectLanguageLabel=选择安装时要使用的语言:
|
||||
; *** Common wizard text
|
||||
ClickNext=单击“下一步”以继续,或单击“取消”以退出安装程序。
|
||||
|
||||
; *** 按钮
|
||||
ButtonBack=< 上一步(&B)
|
||||
ButtonNext=下一步(&N) >
|
||||
ButtonInstall=安装(&I)
|
||||
ButtonOK=确定
|
||||
ButtonCancel=取消
|
||||
ButtonYes=是(&Y)
|
||||
ButtonYesToAll=全是(&A)
|
||||
ButtonNo=否(&N)
|
||||
ButtonNoToAll=全否(&O)
|
||||
ButtonFinish=完成(&F)
|
||||
ButtonBrowse=浏览(&B)...
|
||||
ButtonWizardBrowse=浏览(&R)...
|
||||
ButtonNewFolder=新建文件夹(&M)
|
||||
|
||||
; *** “选择语言”对话框消息
|
||||
SelectLanguageTitle=选择安装语言
|
||||
SelectLanguageLabel=选择安装时要使用的语言。
|
||||
|
||||
; *** 公共向导文字
|
||||
ClickNext=单击“下一步”继续,或单击“取消”退出安装程序。
|
||||
BeveledLabel=
|
||||
BrowseDialogTitle=浏览查找文件夹
|
||||
BrowseDialogLabel=在以下列表中选择一个文件夹,然后单击“确定”。
|
||||
NewFolderName=新建文件夹
|
||||
; *** "Welcome" wizard page
|
||||
WelcomeLabel1=欢迎使用 [name] 安装向导
|
||||
WelcomeLabel2=这将在计算机上安装 [name/ver]。%n%n建议关闭所有其他应用程序再继续。
|
||||
; *** "Password" wizard page
|
||||
WizardPassword=密码
|
||||
PasswordLabel1=此安装受密码保护。
|
||||
PasswordLabel3=请提供密码,然后单击“下一步”以继续。密码区分大小写。
|
||||
PasswordEditLabel=密码(&P):
|
||||
IncorrectPassword=输入的密码不正确。请重试。
|
||||
; *** "License Agreement" wizard page
|
||||
WizardLicense=许可协议
|
||||
LicenseLabel=请在继续操作前阅读以下重要信息。
|
||||
LicenseLabel3=请阅读以下许可协议。必须接受此协议条款才可继续安装。
|
||||
LicenseAccepted=我接受协议(&A)
|
||||
LicenseNotAccepted=我不接受协议(&D)
|
||||
; *** "Information" wizard pages
|
||||
WizardInfoBefore=信息
|
||||
InfoBeforeLabel=请在继续操作前阅读以下重要信息。
|
||||
InfoBeforeClickLabel=准备好继续安装后,单击“下一步”。
|
||||
WizardInfoAfter=信息
|
||||
InfoAfterLabel=请在继续操作前阅读以下重要信息。
|
||||
InfoAfterClickLabel=准备好继续安装后,单击“下一步”。
|
||||
; *** "User Information" wizard page
|
||||
WizardUserInfo=用户信息
|
||||
UserInfoDesc=请输入你的信息。
|
||||
UserInfoName=用户名(&U):
|
||||
UserInfoOrg=组织(&O):
|
||||
UserInfoSerial=序列号(&S):
|
||||
UserInfoNameRequired=必须输入名称。
|
||||
; *** "Select Destination Location" wizard page
|
||||
WizardSelectDir=选择目标位置
|
||||
SelectDirDesc=应将 [name] 安装到哪里?
|
||||
SelectDirLabel3=安装程序会将 [name] 安装到以下文件夹。
|
||||
SelectDirBrowseLabel=若要继续,单击“下一步”。如果想选择其他文件夹,单击“浏览”。
|
||||
DiskSpaceMBLabel=需要至少 [mb] MB 可用磁盘空间。
|
||||
CannotInstallToNetworkDrive=安装程序无法安装到网络驱动器。
|
||||
CannotInstallToUNCPath=安装程序无法安装到 UNC 路径。
|
||||
InvalidPath=必须输入带驱动器号的完整路径(例如:%n%nC:\APP%n%n)或以下格式的 UNC 路径:%n%n\\server\share
|
||||
InvalidDrive=所选驱动器或 UNC 共享不存在或不可访问。请另外选择。
|
||||
DiskSpaceWarningTitle=磁盘空间不足
|
||||
DiskSpaceWarning=安装程序需要至少 %1 KB 可用空间来安装,但所选驱动器仅有 %2 KB 可用空间。%n%n是否仍要继续?
|
||||
DirNameTooLong=文件夹名称或路径太长。
|
||||
InvalidDirName=文件夹名称无效。
|
||||
BadDirName32=文件夹名不能包含以下任一字符:%n%n%1
|
||||
DirExistsTitle=文件夹存在
|
||||
DirExists=文件夹:%n%n%1%n%n已存在。是否仍要安装到该文件夹?
|
||||
DirDoesntExistTitle=文件夹不存在
|
||||
DirDoesntExist=文件夹:%n%n%1%n%n不存在。是否要创建该文件夹?
|
||||
; *** "Select Components" wizard page
|
||||
WizardSelectComponents=选择组件
|
||||
SelectComponentsDesc=应安装哪些组件?
|
||||
SelectComponentsLabel2=选择希望安装的组件;清除不希望安装的组件。准备就绪后单击“下一步”以继续。
|
||||
FullInstallation=完全安装
|
||||
BrowseDialogTitle=浏览文件夹
|
||||
BrowseDialogLabel=在下列列表中选择一个文件夹,然后单击“确定”。
|
||||
NewFolderName=新建文件夹
|
||||
|
||||
; *** “欢迎”向导页
|
||||
WelcomeLabel1=欢迎使用 [name] 安装向导
|
||||
WelcomeLabel2=现在将安装 [name/ver] 到您的电脑中。%n%n推荐您在继续安装前关闭所有其它应用程序。
|
||||
|
||||
; *** “密码”向导页
|
||||
WizardPassword=密码
|
||||
PasswordLabel1=这个安装程序有密码保护。
|
||||
PasswordLabel3=请输入密码,然后单击“下一步”继续。密码区分大小写。
|
||||
PasswordEditLabel=密码(&P):
|
||||
IncorrectPassword=您输入的密码不正确,请重试。
|
||||
|
||||
; *** “许可协议”向导页
|
||||
WizardLicense=许可协议
|
||||
LicenseLabel=继续安装前请阅读下列重要信息。
|
||||
LicenseLabel3=请仔细阅读下列许可协议。您在继续安装前必须同意这些协议条款。
|
||||
LicenseAccepted=我同意此协议(&A)
|
||||
LicenseNotAccepted=我不同意此协议(&D)
|
||||
|
||||
; *** “信息”向导页
|
||||
WizardInfoBefore=信息
|
||||
InfoBeforeLabel=请在继续安装前阅读下列重要信息。
|
||||
InfoBeforeClickLabel=如果您想继续安装,单击“下一步”。
|
||||
WizardInfoAfter=信息
|
||||
InfoAfterLabel=请在继续安装前阅读下列重要信息。
|
||||
InfoAfterClickLabel=如果您想继续安装,单击“下一步”。
|
||||
|
||||
; *** “用户信息”向导页
|
||||
WizardUserInfo=用户信息
|
||||
UserInfoDesc=请输入您的信息。
|
||||
UserInfoName=用户名(&U):
|
||||
UserInfoOrg=组织(&O):
|
||||
UserInfoSerial=序列号(&S):
|
||||
UserInfoNameRequired=您必须输入名字。
|
||||
|
||||
; *** “选择目标目录”向导面
|
||||
WizardSelectDir=选择目标位置
|
||||
SelectDirDesc=您想将 [name] 安装在什么地方?
|
||||
SelectDirLabel3=安装程序将安装 [name] 到下列文件夹中。
|
||||
SelectDirBrowseLabel=单击“下一步”继续。如果您想选择其它文件夹,单击“浏览”。
|
||||
DiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。
|
||||
DiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。
|
||||
CannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。
|
||||
CannotInstallToUNCPath=安装程序无法安装到一个UNC路径。
|
||||
InvalidPath=您必须输入一个带驱动器卷标的完整路径,例如:%n%nC:\APP%n%n或下列形式的 UNC 路径:%n%n\\server\share
|
||||
InvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选选择其它位置。
|
||||
DiskSpaceWarningTitle=没有足够的磁盘空间
|
||||
DiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装,但选定驱动器只有 %2 KB 的可用空间。%n%n您一定要继续吗?
|
||||
DirNameTooLong=文件夹名或路径太长。
|
||||
InvalidDirName=文件夹名是无效的。
|
||||
BadDirName32=文件夹名不能包含下列任何字符:%n%n%1
|
||||
DirExistsTitle=文件夹存在
|
||||
DirExists=文件夹:%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗?
|
||||
DirDoesntExistTitle=文件夹不存在
|
||||
DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此目录吗?
|
||||
|
||||
; *** “选择组件”向导页
|
||||
WizardSelectComponents=选择组件
|
||||
SelectComponentsDesc=您想安装哪些程序的组件?
|
||||
SelectComponentsLabel2=选择您想要安装的组件;清除您不想安装的组件。然后单击“下一步”继续。
|
||||
FullInstallation=完全安装
|
||||
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||
CompactInstallation=简洁安装
|
||||
CustomInstallation=自定义安装
|
||||
NoUninstallWarningTitle=组件存在
|
||||
NoUninstallWarning=安装程序检测到计算机上已安装以下组件:%n%n%1%n%n取消选择这些组件将不会卸载它们。%n%n是否仍要继续?
|
||||
CompactInstallation=简洁安装
|
||||
CustomInstallation=自定义安装
|
||||
NoUninstallWarningTitle=组件存在
|
||||
NoUninstallWarning=安装程序侦测到下列组件已在您的电脑中安装。:%n%n%1%n%n取消选定这些组件将不能卸载它们。%n%n您一定要继续吗?
|
||||
ComponentSize1=%1 KB
|
||||
ComponentSize2=%1 MB
|
||||
ComponentsDiskSpaceMBLabel=当前选择需要至少 [mb] MB 磁盘空间。
|
||||
; *** "Select Additional Tasks" wizard page
|
||||
WizardSelectTasks=选择其他任务
|
||||
SelectTasksDesc=应执行哪些其他任务?
|
||||
SelectTasksLabel2=选择安装 [name] 时希望安装程序来执行的其他任务,然后单击“下一步”。
|
||||
; *** "Select Start Menu Folder" wizard page
|
||||
WizardSelectProgramGroup=选择开始菜单文件夹
|
||||
SelectStartMenuFolderDesc=安装程序应将程序的快捷方式放置到哪里?
|
||||
SelectStartMenuFolderLabel3=安装程序将在以下开始菜单文件夹中创建该程序的快捷方式。
|
||||
SelectStartMenuFolderBrowseLabel=若要继续,单击“下一步”。如果想选择其他文件夹,单击“浏览”。
|
||||
MustEnterGroupName=必须输入文件夹名。
|
||||
GroupNameTooLong=文件夹名称或路径太长。
|
||||
InvalidGroupName=文件夹名称无效。
|
||||
BadGroupName=文件夹名不能保护以下任一字符:%n%n%1
|
||||
NoProgramGroupCheck2=不创建开始菜单文件夹(&D)
|
||||
; *** "Ready to Install" wizard page
|
||||
WizardReady=安装准备就绪
|
||||
ReadyLabel1=安装程序现已准备好在计算机上安装 [name]。
|
||||
ReadyLabel2a=单击“安装”以继续安装,如想查看或更改任何设置则单击"返回"。
|
||||
ReadyLabel2b=单击“安装”以继续安装。
|
||||
ReadyMemoUserInfo=用户信息:
|
||||
ReadyMemoDir=目标位置:
|
||||
ReadyMemoType=安装程序类型:
|
||||
ReadyMemoComponents=所选组件:
|
||||
ReadyMemoGroup=开始菜单文件夹:
|
||||
ReadyMemoTasks=其他任务:
|
||||
; *** "Preparing to Install" wizard page
|
||||
WizardPreparing=正在准备安装
|
||||
PreparingDesc=安装程序正准备在计算机上安装 [name]。
|
||||
PreviousInstallNotCompleted=上一个程序的安装/删除未完成。需重启计算机以完成该安装。%n%n重启计算机后,重新运行安装程序以完成 [name] 的安装。
|
||||
CannotContinue=安装程序无法继续。请单击"取消"以退出。
|
||||
ApplicationsFound=以下应用程序正在使用需要通过安装程序进行更新的文件。建议允许安装程序自动关闭这些应用程序。
|
||||
ApplicationsFound2=以下应用程序正在使用需要通过安装程序进行更新的文件。建议允许安装程序自动关闭这些应用程序。完成安装后,安装程序将尝试重启应用程序。
|
||||
CloseApplications=自动关闭应用程序(&A)
|
||||
DontCloseApplications=不关闭应用程序(&D)
|
||||
ErrorCloseApplications=安装程序无法自动关闭所有应用程序。建议在继续操作之前先关闭所有使用需通过安装程序进行更新的文件的应用程序。
|
||||
; *** "Installing" wizard page
|
||||
WizardInstalling=正在安装
|
||||
InstallingLabel=安装程序正在计算机上安装 [name],请稍等。
|
||||
; *** "Setup Completed" wizard page
|
||||
FinishedHeadingLabel=完成 [name] 安装向导
|
||||
FinishedLabelNoIcons=安装程序已在计算机上完成安装 [name]。
|
||||
FinishedLabel=安装程序已在计算机上完成安装 [name]。通过选择安装的快捷方式可以启动该应用程序。
|
||||
ClickFinish=单击“完成”以退出安装程序。
|
||||
FinishedRestartLabel=要完成 [name] 的安装,安装程序必须重启计算机。是否要立即重启?
|
||||
FinishedRestartMessage=要完成 [name] 的安装,安装程序必须重启计算机。%n%n是否要立即重启?
|
||||
ShowReadmeCheck=是,我希望查看 README 文件
|
||||
YesRadio=是,立即重启计算机(&Y)
|
||||
NoRadio=否,我将稍后重启计算机(&N)
|
||||
; used for example as 'Run MyProg.exe'
|
||||
RunEntryExec=运行 %1
|
||||
; used for example as 'View Readme.txt'
|
||||
RunEntryShellExec=查看 %1
|
||||
; *** "Setup Needs the Next Disk" stuff
|
||||
ChangeDiskTitle=安装程序需要下一个磁盘
|
||||
SelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果此磁盘上的文件可在以下文件夹外的其他文件夹中找到,请输入正确路径或单击“浏览”。
|
||||
PathLabel=路径(&P):
|
||||
FileNotInDir2=在“%2”中无法定位文件“%1”。请插入正确的磁盘或选择其他文件夹。
|
||||
SelectDirectoryLabel=请指定下一个磁盘的位置。
|
||||
; *** Installation phase messages
|
||||
SetupAborted=安装程序未完成。%n%n请更正问题并重新运行安装程序。
|
||||
EntryAbortRetryIgnore=单击“重试”以再次尝试,单击“忽略”以继续,或单击“中止”以取消安装。
|
||||
; *** Installation status messages
|
||||
StatusClosingApplications=正在关闭应用程序...
|
||||
StatusCreateDirs=正在创建目录...
|
||||
StatusExtractFiles=正在解压缩文件...
|
||||
StatusCreateIcons=正在创建快捷方式...
|
||||
StatusCreateIniEntries=正在创建 INI 项...
|
||||
StatusCreateRegistryEntries=正在创建注册表项...
|
||||
StatusRegisterFiles=正在注册文件...
|
||||
StatusSavingUninstall=正在保存卸载信息...
|
||||
StatusRunProgram=正在完成安装...
|
||||
StatusRestartingApplications=正在重启应用程序...
|
||||
StatusRollback=正在回退更改...
|
||||
; *** Misc. errors
|
||||
ErrorInternal2=内部错误: %1
|
||||
ErrorFunctionFailedNoCode=%1 失败
|
||||
ErrorFunctionFailed=%1 失败;代码 %2
|
||||
ErrorFunctionFailedWithMessage=%1 失败;代码 %2。%n%3
|
||||
ErrorExecutingProgram=无法执行文件:%n%1
|
||||
; *** Registry errors
|
||||
ErrorRegOpenKey=打开注册表项时出错:%n%1\%2
|
||||
ErrorRegCreateKey=创建注册表项时出错:%n%1\%2
|
||||
ErrorRegWriteKey=写入注册表项时出错:%n%1\%2
|
||||
; *** INI errors
|
||||
ErrorIniEntry=在文件“%1”中创建 INI 项时出错。
|
||||
; *** File copying errors
|
||||
FileAbortRetryIgnore=单击“重试”以再次操作,单击“忽略”以跳过此文件(不建议此操作),或单击“中止”以取消安装。
|
||||
FileAbortRetryIgnore2=单击“重试”以再次操作,单击“忽略”以继续(不建议此操作),或单击“中止”以取消安装。
|
||||
SourceIsCorrupted=源文件已损坏
|
||||
SourceDoesntExist=源文件“%1”不存在
|
||||
ExistingFileReadOnly=现有文件被标记为只读状态。%n%n单击“重试”以删除只读特性并重试,单击“忽略”以跳过此文件,或单击“中止”以取消安装。
|
||||
ErrorReadingExistingDest=尝试读取现有文件时出错:
|
||||
FileExists=该文件已存在。%n%n是否要安装程序覆盖它?
|
||||
ExistingFileNewer=现有文件比安装程序正尝试安装的文件更新。建议保留现有文件。%n%n是否要保留现有文件?
|
||||
ErrorChangingAttr=尝试更改现有文件特性出错:
|
||||
ErrorCreatingTemp=尝试在目标目录创建文件时出错:
|
||||
ErrorReadingSource=尝试读取源文件时出错:
|
||||
ErrorCopying=尝试复制文件时出错:
|
||||
ErrorReplacingExistingFile=尝试替换现有文件时出错:
|
||||
ErrorRestartReplace=RestartReplace 失败:
|
||||
ErrorRenamingTemp=尝试在目标目录重命名文件时出错:
|
||||
ErrorRegisterServer=无法注册 DLL/OCX: %1
|
||||
ErrorRegSvr32Failed=RegSvr32 失败,退出代码为 %1
|
||||
ErrorRegisterTypeLib=无法注册类型库: %1
|
||||
; *** Post-installation errors
|
||||
ErrorOpeningReadme=尝试打开 README 文件时出错。
|
||||
ErrorRestartingComputer=安装程序无法重启计算机。请手动执行此操作。
|
||||
; *** Uninstaller messages
|
||||
UninstallNotFound=文件“%1”不存在。无法安装。
|
||||
UninstallOpenError=无法打开文件“%1”。无法卸载
|
||||
UninstallUnsupportedVer=卸载日志“%1”的格式无法被此版本的卸载程序识别。无法卸载
|
||||
UninstallUnknownEntry=卸载日志中发现未知条目(%1)
|
||||
ConfirmUninstall=确定要彻底删除 %1 和及其全部组件?
|
||||
UninstallOnlyOnWin64=仅可在 64 位 Windows 上卸载此安装。
|
||||
OnlyAdminCanUninstall=仅具有管理权限的用户才可卸载此安装。
|
||||
UninstallStatusLabel=正从计算机删除 %1,请稍等。
|
||||
UninstalledAll=已成功从计算机上删除 %1。
|
||||
UninstalledMost=%1 卸载完成。%n%n无法删除一些元素。可将其手动删除。
|
||||
UninstalledAndNeedsRestart=要完成 %1 的卸载,必须重启计算机。%n%n是否要立即重启?
|
||||
UninstallDataCorrupted=“%1”文件已损坏。无法卸载
|
||||
; *** Uninstallation phase messages
|
||||
ConfirmDeleteSharedFileTitle=删除共享文件?
|
||||
ConfirmDeleteSharedFile2=系统表示以下共享文件不再被任何程序使用。是否要卸载删除此共享文件?%n%n如果在有程序仍在使用此文件而它被删除,则程序可能不会正常运行。如果不确定,请选择“否”。将文件留住系统上不会造成任何问题。
|
||||
SharedFileNameLabel=文件名:
|
||||
SharedFileLocationLabel=位置:
|
||||
WizardUninstalling=卸载状态
|
||||
StatusUninstalling=正在卸载 %1...
|
||||
ComponentsDiskSpaceGBLabel=当前选择的组件至少需要 [gb] GB 的磁盘空间。
|
||||
ComponentsDiskSpaceMBLabel=当前选择的组件至少需要 [mb] MB 的磁盘空间。
|
||||
|
||||
; *** “选择附加任务”向导页
|
||||
WizardSelectTasks=选择附加任务
|
||||
SelectTasksDesc=您想要安装程序执行哪些附加任务?
|
||||
SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后单击“下一步”。
|
||||
|
||||
; *** “选择开始菜单文件夹”向导页
|
||||
WizardSelectProgramGroup=选择开始菜单文件夹
|
||||
SelectStartMenuFolderDesc=您想在哪里放置程序的快捷方式?
|
||||
SelectStartMenuFolderLabel3=安装程序现在将在下列开始菜单文件夹中创建程序的快捷方式。
|
||||
SelectStartMenuFolderBrowseLabel=单击“下一步”继续。如果您想选择其它文件夹,单击“浏览”。
|
||||
MustEnterGroupName=您必须输入一个文件夹名。
|
||||
GroupNameTooLong=文件夹名或路径太长。
|
||||
InvalidGroupName=文件夹名是无效的。
|
||||
BadGroupName=文件夹名不能包含下列任何字符:%n%n%1
|
||||
NoProgramGroupCheck2=不创建开始菜单文件夹(&D)
|
||||
|
||||
; *** “准备安装”向导页
|
||||
WizardReady=准备安装
|
||||
ReadyLabel1=安装程序现在准备开始安装 [name] 到您的电脑中。
|
||||
ReadyLabel2a=单击“安装”继续此安装程序。如果您想要回顾或改变设置,请单击“上一步”。
|
||||
ReadyLabel2b=单击“安装”继续此安装程序?
|
||||
ReadyMemoUserInfo=用户信息:
|
||||
ReadyMemoDir=目标位置:
|
||||
ReadyMemoType=安装类型:
|
||||
ReadyMemoComponents=选定组件:
|
||||
ReadyMemoGroup=开始菜单文件夹:
|
||||
ReadyMemoTasks=附加任务:
|
||||
|
||||
; *** “正在准备安装”向导页
|
||||
WizardPreparing=正在准备安装
|
||||
PreparingDesc=安装程序正在准备安装 [name] 到您的电脑中。
|
||||
PreviousInstallNotCompleted=先前程序的安装/卸载未完成。您需要重新启动您的电脑才能完成安装。%n%n在重新启动电脑后,再运行安装完成 [name] 的安装。
|
||||
CannotContinue=安装程序不能继续。请单击“取消”退出。
|
||||
ApplicationsFound=下列应用程序正在使用的文件需要更新设置。它是建议您允许安装程序自动关闭这些应用程序。
|
||||
ApplicationsFound2=下列应用程序正在使用的文件需要更新设置。它是建议您允许安装程序自动关闭这些应用程序。安装完成后,安装程序将尝试重新启动应用程序。
|
||||
CloseApplications=自动关闭该应用程序(&A)
|
||||
DontCloseApplications=不要关闭该应用程序(D)
|
||||
ErrorCloseApplications=安装程序无法自动关闭所有应用程序。在继续之前,我们建议您关闭所有使用需要更新的安装程序文件。
|
||||
PrepareToInstallNeedsRestart=安装程序必须重新启动计算机。重新启动计算机后,请再次运行安装程序以完成 [name] 的安装。%n%n是否立即重新启动?
|
||||
|
||||
; *** “正在安装”向导页
|
||||
WizardInstalling=正在安装
|
||||
InstallingLabel=安装程序正在安装 [name] 到您的电脑中,请稍等。
|
||||
|
||||
; *** “安装完成”向导页
|
||||
FinishedHeadingLabel=[name] 安装完成
|
||||
FinishedLabelNoIcons=安装程序已在您的电脑中安装了 [name]。
|
||||
FinishedLabel=安装程序已在您的电脑中安装了 [name]。此应用程序可以通过选择安装的快捷方式运行。
|
||||
ClickFinish=单击“完成”退出安装程序。
|
||||
FinishedRestartLabel=要完成 [name] 的安装,安装程序必须重新启动您的电脑。您想现在重新启动吗?
|
||||
FinishedRestartMessage=要完成 [name] 的安装,安装程序必须重新启动您的电脑。%n%n您想现在重新启动吗?
|
||||
ShowReadmeCheck=是,您想查阅自述文件
|
||||
YesRadio=是,立即重新启动电脑(&Y)
|
||||
NoRadio=否,稍后重新启动电脑(&N)
|
||||
; 用于象“运行 MyProg.exe”
|
||||
RunEntryExec=运行 %1
|
||||
; 用于象“查阅 Readme.txt”
|
||||
RunEntryShellExec=查阅 %1
|
||||
|
||||
; *** “安装程序需要下一张磁盘”提示
|
||||
ChangeDiskTitle=安装程序需要下一张磁盘
|
||||
SelectDiskLabel2=请插入磁盘 %1 并单击“确定”。%n%n如果这个磁盘中的文件不能在不同于下列显示的文件夹中找到,输入正确的路径或单击“浏览”。
|
||||
PathLabel=路径(&P):
|
||||
FileNotInDir2=文件“%1”不能在“%2”定位。请插入正确的磁盘或选择其它文件夹。
|
||||
SelectDirectoryLabel=请指定下一张磁盘的位置。
|
||||
|
||||
; *** 安装状态消息
|
||||
SetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。
|
||||
AbortRetryIgnoreSelectAction=选项
|
||||
AbortRetryIgnoreRetry=重试(&T)
|
||||
AbortRetryIgnoreIgnore=忽略错误并继续(&I)
|
||||
AbortRetryIgnoreCancel=关闭安装程序
|
||||
|
||||
; *** 安装状态消息
|
||||
StatusClosingApplications=正在关闭应用程序...
|
||||
StatusCreateDirs=正在创建目录...
|
||||
StatusExtractFiles=正在解压缩文件...
|
||||
StatusCreateIcons=正在创建快捷方式...
|
||||
StatusCreateIniEntries=正在创建 INI 条目...
|
||||
StatusCreateRegistryEntries=正在创建注册表条目...
|
||||
StatusRegisterFiles=正在注册文件...
|
||||
StatusSavingUninstall=正在保存卸载信息...
|
||||
StatusRunProgram=正在完成安装...
|
||||
StatusRestartingApplications=正在重启应用程序...
|
||||
StatusRollback=正在撤销更改...
|
||||
|
||||
; *** 其它错误
|
||||
ErrorInternal2=内部错误: %1
|
||||
ErrorFunctionFailedNoCode=%1 失败
|
||||
ErrorFunctionFailed=%1 失败;错误代码 %2
|
||||
ErrorFunctionFailedWithMessage=%1 失败;错误代码 %2.%n%3
|
||||
ErrorExecutingProgram=不能执行文件:%n%1
|
||||
|
||||
; *** 注册表错误
|
||||
ErrorRegOpenKey=打开注册表项时出错:%n%1\%2
|
||||
ErrorRegCreateKey=创建注册表项时出错:%n%1\%2
|
||||
ErrorRegWriteKey=写入注册表项时出错:%n%1\%2
|
||||
|
||||
; *** INI 错误
|
||||
ErrorIniEntry=在文件“%1”创建 INI 项目错误。
|
||||
|
||||
; *** 文件复制错误
|
||||
FileAbortRetryIgnoreSkipNotRecommended=跳过这个文件 (不推荐)(&S)
|
||||
FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续 (不推荐)(&I)
|
||||
SourceIsCorrupted=源文件已损坏
|
||||
SourceDoesntExist=源文件“%1”不存在
|
||||
ExistingFileReadOnly2=无法替换现有文件,因为它是只读的。
|
||||
ExistingFileReadOnlyRetry=移除只读属性并重试(&R)
|
||||
ExistingFileReadOnlyKeepExisting=保留现有文件(&K)
|
||||
ErrorReadingExistingDest=尝试读取现有文件时发生一个错误:
|
||||
FileExists=文件已经存在。%n%n您想要安装程序覆盖它吗?
|
||||
ExistingFileNewer=现有的文件新与安装程序要安装的文件。推荐您保留现有文件。%n%n您想要保留现有的文件吗?
|
||||
ErrorChangingAttr=尝试改变下列现有的文件的属性时发生一个错误:
|
||||
ErrorCreatingTemp=尝试在目标目录创建文件时发生一个错误:
|
||||
ErrorReadingSource=尝试读取下列源文件时发生一个错误:
|
||||
ErrorCopying=尝试复制下列文件时发生一个错误:
|
||||
ErrorReplacingExistingFile=尝试替换现有的文件时发生错误:
|
||||
ErrorRestartReplace=重启电脑后替换文件失败:
|
||||
ErrorRenamingTemp=尝试重新命名以下目标目录中的一个文件时发生错误:
|
||||
ErrorRegisterServer=不能注册 DLL/OCX: %1
|
||||
ErrorRegSvr32Failed=RegSvr32 失败;退出代码 %1
|
||||
ErrorRegisterTypeLib=不能注册类型库: %1
|
||||
|
||||
; *** 卸载显示名字标记
|
||||
; used for example as 'My Program (32-bit)'
|
||||
UninstallDisplayNameMark=%1 (%2)
|
||||
; used for example as 'My Program (32-bit, All users)'
|
||||
UninstallDisplayNameMarks=%1 (%2, %3)
|
||||
UninstallDisplayNameMark32Bit=32位
|
||||
UninstallDisplayNameMark64Bit=64位
|
||||
UninstallDisplayNameMarkAllUsers=所有用户
|
||||
UninstallDisplayNameMarkCurrentUser=当前用户
|
||||
|
||||
; *** 安装后错误
|
||||
ErrorOpeningReadme=当尝试打开自述文件时发生一个错误。
|
||||
ErrorRestartingComputer=安装程序不能重新启动电脑,请手动重启。
|
||||
|
||||
; *** 卸载消息
|
||||
UninstallNotFound=文件“%1”不存在。不能卸载。
|
||||
UninstallOpenError=文件“%1”不能打开。不能卸载。
|
||||
UninstallUnsupportedVer=卸载日志文件“%1”有未被这个版本的卸载器承认的格式。不能卸载
|
||||
UninstallUnknownEntry=在卸载日志中遇到一个未知的条目 (%1)
|
||||
ConfirmUninstall=您确认想要完全删除 %1 及它的所有组件吗?
|
||||
UninstallOnlyOnWin64=这个安装程序只能在 64 位 Windows 中进行卸载。
|
||||
OnlyAdminCanUninstall=这个安装的程序只能是有管理员权限的用户才能卸载。
|
||||
UninstallStatusLabel=正在从您的电脑中删除 %1,请等待。
|
||||
UninstalledAll=%1 已顺利地从您的电脑中删除。
|
||||
UninstalledMost=%1 卸载完成。%n%n有一些内容不能被删除。您可以手工删除它们。
|
||||
UninstalledAndNeedsRestart=要完成 %1 的卸载,您的电脑必须重新启动。%n%n您现在想重新启动电脑吗?
|
||||
UninstallDataCorrupted=“%1”文件被破坏,不能卸载
|
||||
|
||||
; *** 卸载状态消息
|
||||
ConfirmDeleteSharedFileTitle=删除共享文件吗?
|
||||
ConfirmDeleteSharedFile2=系统中包含的下列共享文件已经不被其它程序使用。您想要卸载程序删除这些共享文件吗?%n%n如果这些文件被删除,但还有程序正在使用这些文件,这些程序可能不能正确执行。如果您不能确定,选择“否”。把这些文件保留在系统中以免引起问题。
|
||||
SharedFileNameLabel=文件名:
|
||||
SharedFileLocationLabel=位置:
|
||||
WizardUninstalling=卸载状态
|
||||
StatusUninstalling=正在卸载 %1...
|
||||
|
||||
; *** Shutdown block reasons
|
||||
ShutdownBlockReasonInstallingApp=正在安装 %1。
|
||||
ShutdownBlockReasonUninstallingApp=正在卸载 %1。
|
||||
ShutdownBlockReasonInstallingApp=正在安装 %1.
|
||||
ShutdownBlockReasonUninstallingApp=正在卸载 %1.
|
||||
|
||||
; The custom messages below aren't used by Setup itself, but if you make
|
||||
; use of them in your scripts, you'll want to translate them.
|
||||
|
||||
[CustomMessages]
|
||||
NameAndVersion=%1 版本 %2
|
||||
AdditionalIcons=其他快捷方式:
|
||||
CreateDesktopIcon=创建桌面快捷方式(&D)
|
||||
CreateQuickLaunchIcon=创建快速启动快捷方式(&Q)
|
||||
ProgramOnTheWeb=Web 上的 %1
|
||||
UninstallProgram=卸载 %1
|
||||
LaunchProgram=启动 %1
|
||||
AssocFileExtension=将 %1 与 %2 文件扩展名关联(&A)
|
||||
AssocingFileExtension=正将 %1 与 %2 文件扩展名关联...
|
||||
AutoStartProgramGroupDescription=启动:
|
||||
AutoStartProgram=自动启动 %1
|
||||
AddonHostProgramNotFound=无法在所选文件夹中定位 %1。%n%n是否仍要继续?
|
||||
|
||||
NameAndVersion=%1 版本 %2
|
||||
AdditionalIcons=附加快捷方式:
|
||||
CreateDesktopIcon=创建桌面快捷方式(&D)
|
||||
CreateQuickLaunchIcon=创建快速运行栏快捷方式(&Q)
|
||||
ProgramOnTheWeb=%1 网站
|
||||
UninstallProgram=卸载 %1
|
||||
LaunchProgram=运行 %1
|
||||
AssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A)
|
||||
AssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联...
|
||||
AutoStartProgramGroupDescription=启动组:
|
||||
AutoStartProgram=自动启动 %1
|
||||
AddonHostProgramNotFound=%1无法找到您所选择的文件夹。%n%n您想要继续吗?
|
||||
|
||||
|
||||
@@ -1,298 +1,359 @@
|
||||
; *** Inno Setup version 5.5.3+ Traditional Chinese messages ***
|
||||
; *** Inno Setup version 6.0.0+ Chinese Traditional messages ***
|
||||
;
|
||||
; To download user-contributed translations of this file, go to:
|
||||
; http://www.jrsoftware.org/files/istrans/
|
||||
; Name: John Wu, mr.johnwu@gmail.com
|
||||
; Base on 5.5.3+ translations by Samuel Lee, Email: 751555749@qq.com
|
||||
; Translation based on network resource
|
||||
;
|
||||
; Note: When translating this text, do not add periods (.) to the end of
|
||||
; messages that didn't have them already, because on those messages Inno
|
||||
; Setup adds the periods automatically (appending a period would result in
|
||||
; two periods being displayed).
|
||||
|
||||
[LangOptions]
|
||||
; The following three entries are very important. Be sure to read and
|
||||
; understand the '[LangOptions] section' topic in the help file.
|
||||
LanguageName=Traditional Chinese
|
||||
; If Language Name display incorrect, uncomment next line
|
||||
LanguageName=<7e41><9ad4><4e2d><6587>
|
||||
LanguageID=$0404
|
||||
LanguageCodePage=950
|
||||
LanguageCodepage=950
|
||||
; If the language you are translating to requires special font faces or
|
||||
; sizes, uncomment any of the following entries and change them accordingly.
|
||||
;DialogFontName=
|
||||
;DialogFontSize=8
|
||||
;WelcomeFontName=Verdana
|
||||
;WelcomeFontSize=12
|
||||
;TitleFontName=Arial
|
||||
;TitleFontSize=29
|
||||
;CopyrightFontName=Arial
|
||||
;CopyrightFontSize=8
|
||||
DialogFontName=新細明體
|
||||
DialogFontSize=9
|
||||
TitleFontName=Arial
|
||||
TitleFontSize=28
|
||||
WelcomeFontName=新細明體
|
||||
WelcomeFontSize=12
|
||||
CopyrightFontName=新細明體
|
||||
CopyrightFontSize=9
|
||||
|
||||
[Messages]
|
||||
|
||||
; *** Application titles
|
||||
SetupAppTitle=安裝程式
|
||||
SetupWindowTitle=安裝程式 - %1
|
||||
UninstallAppTitle=解除安裝
|
||||
UninstallAppFullTitle=%1 解除安裝
|
||||
SetupAppTitle=安裝程式
|
||||
SetupWindowTitle=%1 安裝程式
|
||||
UninstallAppTitle=解除安裝
|
||||
UninstallAppFullTitle=解除安裝 %1
|
||||
|
||||
; *** Misc. common
|
||||
InformationTitle=資訊
|
||||
ConfirmTitle=確認
|
||||
ErrorTitle=錯誤
|
||||
InformationTitle=訊息
|
||||
ConfirmTitle=確認
|
||||
ErrorTitle=錯誤
|
||||
|
||||
; *** SetupLdr messages
|
||||
SetupLdrStartupMessage=這會安裝 %1。要繼續嗎?
|
||||
LdrCannotCreateTemp=無法建立暫存檔。安裝已中止
|
||||
LdrCannotExecTemp=無法執行暫存目錄中的檔案。安裝已中止
|
||||
SetupLdrStartupMessage=這將會安裝 %1。您想要繼續嗎?
|
||||
LdrCannotCreateTemp=無法建立暫存檔案。安裝程式將會結束。
|
||||
LdrCannotExecTemp=無法執行暫存檔案。安裝程式將會結束。
|
||||
HelpTextNote=
|
||||
|
||||
; *** Startup error messages
|
||||
LastErrorMessage=%1。%n%n錯誤 %2: %3
|
||||
SetupFileMissing=安裝目錄中缺少檔案 %1。請修正問題,或重新取得程式的新複本。
|
||||
SetupFileCorrupt=安裝程式檔案已損毀。請重新取得該程式的複本。
|
||||
SetupFileCorruptOrWrongVer=安裝程式檔案已損毀,或不相容於與此版的安裝程式。請修正問題,或重新取得程式的新複本。
|
||||
InvalidParameter=在命令列上傳遞了無效的參數:%n%n%1
|
||||
SetupAlreadyRunning=安裝程式已在執行中。
|
||||
WindowsVersionNotSupported=此程式不支援電腦所執行的 Windows 版本。
|
||||
WindowsServicePackRequired=此程式需要 %1 Service Pack %2 或更新版本。
|
||||
NotOnThisPlatform=此程式不會在 %1 上執行。
|
||||
OnlyOnThisPlatform=此程式必須在 %1 上執行。
|
||||
OnlyOnTheseArchitectures=此程式只可安裝在專為下列處理器架構設計的 Windows 版本上:%n%n%1
|
||||
MissingWOW64APIs=您執行的 Windows 版本不含安裝程式執行 64 位元安裝所需的功能。若要修正此問題,請安裝 Service Pack %1。
|
||||
WinVersionTooLowError=此程式需要 %1 版 %2 或更新版本。
|
||||
WinVersionTooHighError=此程式無法安裝在 %1 版 %2 或更新版本上。
|
||||
AdminPrivilegesRequired=安裝此程式時,必須以系統管理員身分登入。
|
||||
PowerUserPrivilegesRequired=當您安裝此程式時,必須以系統管理員或 Power Users 群組的成員身分登入。
|
||||
SetupAppRunningError=安裝時偵測到 %1 目前正在執行中。%n%n請立即關閉其所有執行個體。若要繼續,請按一下 [確定]; 若要結束,請按一下 [取消]。
|
||||
UninstallAppRunningError=解除安裝時偵測到 %1 目前正在執行中。%n%n請立即關閉其所有執行個體。若要繼續,請按一下 [確定]; 若要結束,請按一下 [取消]。
|
||||
LastErrorMessage=%1%n%n錯誤 %2: %3
|
||||
SetupFileMissing=安裝資料夾中遺失檔案 %1。請修正此問題或重新取得此軟體。
|
||||
SetupFileCorrupt=安裝檔案已經損毀。請重新取得此軟體。
|
||||
SetupFileCorruptOrWrongVer=安裝檔案已經損毀,或與安裝程式的版本不符。請重新取得此軟體。
|
||||
InvalidParameter=某個無效的變量已被傳遞到了命令列:%n%n%1
|
||||
SetupAlreadyRunning=安裝程式已經在執行。
|
||||
WindowsVersionNotSupported=本安裝程式並不支援目前在電腦所運行的 Windows 版本。
|
||||
WindowsServicePackRequired=本安裝程式需要 %1 Service Pack %2 或更新。
|
||||
NotOnThisPlatform=這個程式無法在 %1 執行。
|
||||
OnlyOnThisPlatform=這個程式必須在 %1 執行。
|
||||
OnlyOnTheseArchitectures=這個程式只能在專門為以下處理器架構而設計的 Windows 上安裝:%n%n%1
|
||||
WinVersionTooLowError=這個程式必須在 %1 版本 %2 或以上的系統執行。
|
||||
WinVersionTooHighError=這個程式無法安裝在 %1 版本 %2 或以上的系統。
|
||||
AdminPrivilegesRequired=您必須登入成系統管理員以安裝這個程式。
|
||||
PowerUserPrivilegesRequired=您必須登入成具有系統管理員或 Power User 權限的使用者以安裝這個程式。
|
||||
SetupAppRunningError=安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 [確定] 繼續,或按 [取消] 離開。
|
||||
UninstallAppRunningError=解除安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 [確定] 繼續,或按 [取消] 離開。
|
||||
|
||||
; *** Startup questions
|
||||
PrivilegesRequiredOverrideTitle=選擇安裝程式安裝模式
|
||||
PrivilegesRequiredOverrideInstruction=選擇安裝模式
|
||||
PrivilegesRequiredOverrideText1=可以為所有使用者安裝 %1 (需要系統管理權限),或是僅為您安裝。
|
||||
PrivilegesRequiredOverrideText2=可以僅為您安裝 %1,或是為所有使用者安裝 (需要系統管理權限)。
|
||||
PrivilegesRequiredOverrideAllUsers=為所有使用者安裝 (&A)
|
||||
PrivilegesRequiredOverrideAllUsersRecommended=為所有使用者安裝 (建議選項) (&A)
|
||||
PrivilegesRequiredOverrideCurrentUser=僅為我安裝 (&M)
|
||||
PrivilegesRequiredOverrideCurrentUserRecommended=僅為我安裝 (建議選項) (&M)
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorCreatingDir=安裝程式無法建立目錄 "%1"
|
||||
ErrorTooManyFilesInDir=因為目錄 "%1" 包含太多檔案,所以無法在其中建立檔案
|
||||
ErrorCreatingDir=安裝程式無法建立資料夾“%1”。
|
||||
ErrorTooManyFilesInDir=無法在資料夾“%1”內建立檔案,因為資料夾內有太多的檔案。
|
||||
|
||||
; *** Setup common messages
|
||||
ExitSetupTitle=結束安裝
|
||||
ExitSetupMessage=安裝未完成。若立即結束,將不會安裝程式。%n%n您可以稍後再執行安裝程式來完成安裝。%n%n要結束安裝嗎?
|
||||
AboutSetupMenuItem=關於安裝程式(&A)...
|
||||
AboutSetupTitle=關於安裝程式
|
||||
AboutSetupMessage=%1 版 %2%n%3%n%n%1 首頁:%n%4
|
||||
ExitSetupTitle=結束安裝程式
|
||||
ExitSetupMessage=安裝尚未完成。如果您現在結束安裝程式,這個程式將不會被安裝。%n%n您可以稍後再執行安裝程式以完成安裝程序。您現在要結束安裝程式嗎?
|
||||
AboutSetupMenuItem=關於安裝程式(&A)...
|
||||
AboutSetupTitle=關於安裝程式
|
||||
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 網址:%n%4
|
||||
AboutSetupNote=
|
||||
TranslatorNote=
|
||||
|
||||
; *** Buttons
|
||||
ButtonBack=< 上一步(&B)
|
||||
ButtonNext=下一步(&N) >
|
||||
ButtonInstall=安裝(&I)
|
||||
ButtonOK=確定
|
||||
ButtonCancel=取消
|
||||
ButtonYes=是(&Y)
|
||||
ButtonYesToAll=全部皆是(&A)
|
||||
ButtonNo=否(&N)
|
||||
ButtonNoToAll=全部皆否(&O)
|
||||
ButtonFinish=完成(&F)
|
||||
ButtonBrowse=瀏覽(&B)...
|
||||
ButtonWizardBrowse=瀏覽(&R)...
|
||||
ButtonNewFolder=建立新資料夾(&M)
|
||||
ButtonBack=< 上一步(&B)
|
||||
ButtonInstall=安裝(&I)
|
||||
ButtonNext=下一步(&N) >
|
||||
ButtonOK=確定
|
||||
ButtonCancel=取消
|
||||
ButtonYes=是(&Y)
|
||||
ButtonYesToAll=全部皆是(&A)
|
||||
ButtonNo=否(&N)
|
||||
ButtonNoToAll=全部皆否(&O)
|
||||
ButtonFinish=完成(&F)
|
||||
ButtonBrowse=瀏覽(&B)...
|
||||
ButtonWizardBrowse=瀏覽(&R)...
|
||||
ButtonNewFolder=建立新資料夾(&M)
|
||||
|
||||
; *** "Select Language" dialog messages
|
||||
SelectLanguageTitle=選取安裝程式語言
|
||||
SelectLanguageLabel=選取安裝期間所要使用的語言:
|
||||
SelectLanguageTitle=選擇安裝語言
|
||||
SelectLanguageLabel=選擇在安裝過程中使用的語言:
|
||||
|
||||
; *** Common wizard text
|
||||
ClickNext=若要繼續,請按一下 [下一步]; 若要結束安裝,請按一下 [取消]。
|
||||
ClickNext=按 [下一步] 繼續安裝,或按 [取消] 結束安裝程式。
|
||||
BeveledLabel=
|
||||
BrowseDialogTitle=瀏覽資料夾
|
||||
BrowseDialogLabel=請從下列清單中選取資料夾,然後按一下 [確定]。
|
||||
NewFolderName=新增資料夾
|
||||
BrowseDialogTitle=瀏覽資料夾
|
||||
BrowseDialogLabel=在下面的資料夾列表中選擇一個資料夾,然後按 [確定]。
|
||||
NewFolderName=新資料夾
|
||||
|
||||
; *** "Welcome" wizard page
|
||||
WelcomeLabel1=歡迎使用 [name] 安裝精靈
|
||||
WelcomeLabel2=這會在您的電腦上安裝 [name/ver]。%n%n建議您先關閉所有其他應用程式,然後再繼續。
|
||||
WelcomeLabel1=歡迎使用 [name] 安裝程式
|
||||
WelcomeLabel2=這個安裝程式將會安裝 [name/ver] 到您的電腦。%n%n我們強烈建議您在安裝過程中關閉其它的應用程式,以避免與安裝程式發生沖突。
|
||||
|
||||
; *** "Password" wizard page
|
||||
WizardPassword=密碼
|
||||
PasswordLabel1=此安裝受密碼保護。
|
||||
PasswordLabel3=請提供密碼,然後按一下 [下一步] 以繼續。密碼區分大小寫。
|
||||
PasswordEditLabel=密碼(&P):
|
||||
IncorrectPassword=輸入的密碼不正確。請再試一次。
|
||||
WizardPassword=密碼
|
||||
PasswordLabel1=這個安裝程式具有密碼保護。
|
||||
PasswordLabel3=請輸入密碼,然後按 [下一步] 繼續。密碼是區分大小寫的。
|
||||
PasswordEditLabel=密碼(&P):
|
||||
IncorrectPassword=您輸入的密碼不正確,請重新輸入。
|
||||
|
||||
; *** "License Agreement" wizard page
|
||||
WizardLicense=授權合約
|
||||
LicenseLabel=請先閱讀下列重要資訊再繼續。
|
||||
LicenseLabel3=請閱讀下列授權合約。您必須接受此合約條款,才能繼續安裝。
|
||||
LicenseAccepted=我接受合約(&A)
|
||||
LicenseNotAccepted=我不接受合約(&D)
|
||||
WizardLicense=授權合約
|
||||
LicenseLabel=請閱讀以下授權合約。
|
||||
LicenseLabel3=請閱讀以下授權合約,您必須接受合約的各項條款才能繼續安裝。
|
||||
LicenseAccepted=我同意(&A)
|
||||
LicenseNotAccepted=我不同意(&D)
|
||||
|
||||
; *** "Information" wizard pages
|
||||
WizardInfoBefore=資訊
|
||||
InfoBeforeLabel=請先閱讀下列重要資訊再繼續。
|
||||
InfoBeforeClickLabel=當您準備好要繼續安裝時,請按一下 [下一步]。
|
||||
WizardInfoAfter=資訊
|
||||
InfoAfterLabel=請先閱讀下列重要資訊再繼續。
|
||||
InfoAfterClickLabel=當您準備好要繼續安裝時,請按一下 [下一步]。
|
||||
WizardInfoBefore=訊息
|
||||
InfoBeforeLabel=在繼續安裝之前請閱讀以下重要資訊。
|
||||
InfoBeforeClickLabel=當您準備好繼續安裝,請按 [下一步]。
|
||||
WizardInfoAfter=訊息
|
||||
InfoAfterLabel=在繼續安裝之前請閱讀以下重要資訊。
|
||||
InfoAfterClickLabel=當您準備好繼續安裝,請按 [下一步]。
|
||||
|
||||
; *** "User Information" wizard page
|
||||
WizardUserInfo=使用者資訊
|
||||
UserInfoDesc=請輸入您的資訊。
|
||||
UserInfoName=使用者名稱(&U):
|
||||
UserInfoOrg=組織(&O):
|
||||
UserInfoSerial=序號(&S):
|
||||
UserInfoNameRequired=必須輸入名稱。
|
||||
WizardUserInfo=使用者資訊
|
||||
UserInfoDesc=請輸入您的資料。
|
||||
UserInfoName=使用者名稱(&U):
|
||||
UserInfoOrg=組織(&O):
|
||||
UserInfoSerial=序號(&S):
|
||||
UserInfoNameRequired=您必須輸入您的名稱。
|
||||
|
||||
; *** "Select Destination Location" wizard page
|
||||
WizardSelectDir=選取目的地位置
|
||||
SelectDirDesc=應將 [name] 安裝在何處?
|
||||
SelectDirLabel3=安裝程式會將 [name] 安裝在下列資料夾中。
|
||||
SelectDirBrowseLabel=若要繼續,請按一下 [下一步]。若您想選取不同的資料夾,請按一下 [瀏覽]。
|
||||
DiskSpaceMBLabel=至少須有 [mb] MB 的可用磁碟空間。
|
||||
CannotInstallToNetworkDrive=安裝程式無法安裝到網路磁碟機。
|
||||
CannotInstallToUNCPath=安裝程式無法安裝到 UNC 路徑。
|
||||
InvalidPath=必須輸入包含磁碟機代號的完整路徑,例如:%n%nC:\APP%n%n或輸入下列格式的 UNC 路徑:%n%n\\伺服器\共用
|
||||
InvalidDrive=選取的磁碟機或 UNC 共用不存在或無法存取。請選取其他磁碟機或 UNC 共用。
|
||||
DiskSpaceWarningTitle=磁碟空間不足
|
||||
DiskSpaceWarning=安裝程式至少需要 %1 KB 的可用空間才能安裝,但所選磁碟機的可用空間只有 %2 KB。%n%n仍要繼續嗎?
|
||||
DirNameTooLong=資料夾名稱或路徑過長。
|
||||
InvalidDirName=此資料夾名稱無效。
|
||||
BadDirName32=資料夾名稱不得包含下列任一字元:%n%n%1
|
||||
DirExistsTitle=資料夾已存在
|
||||
DirExists=已有資料夾 %n%n%1%n%n。仍要安裝到該資料夾嗎?
|
||||
DirDoesntExistTitle=資料夾不存在
|
||||
DirDoesntExist=資料夾 %n%n%1%n%n 不存在。要建立該資料夾嗎?
|
||||
WizardSelectDir=選擇目的資料夾
|
||||
SelectDirDesc=選擇安裝程式安裝 [name] 的位置。
|
||||
SelectDirLabel3=安裝程式將會把 [name] 安裝到下面的資料夾。
|
||||
SelectDirBrowseLabel=按 [下一步] 繼續,如果您想選擇另一個資料夾,請按 [瀏覽]。
|
||||
DiskSpaceMBLabel=最少需要 [mb] MB 磁碟空間。
|
||||
CannotInstallToNetworkDrive=安裝程式無法安裝於網絡磁碟機。
|
||||
CannotInstallToUNCPath=安裝程式無法安裝於 UNC 路徑。
|
||||
InvalidPath=您必須輸入完整的路徑名稱及磁碟機代碼。%n%n例如 C:\App 或 UNC 路徑格式 \\伺服器\共用資料夾。
|
||||
InvalidDrive=您選取的磁碟機或 UNC 名稱不存在或無法存取,請選擇其他的目的地。
|
||||
DiskSpaceWarningTitle=磁碟空間不足
|
||||
DiskSpaceWarning=安裝程式需要至少 %1 KB 的磁碟空間,您所選取的磁碟只有 %2 KB 可用空間。%n%n您要繼續安裝嗎?
|
||||
DirNameTooLong=資料夾名稱或路徑太長。
|
||||
InvalidDirName=資料夾名稱不正確。
|
||||
BadDirName32=資料夾名稱不得包含以下特殊字元:%n%n%1
|
||||
DirExistsTitle=資料夾已經存在
|
||||
DirExists=資料夾:%n%n%1%n%n 已經存在。仍要安裝到該資料夾嗎?
|
||||
DirDoesntExistTitle=資料夾不存在
|
||||
DirDoesntExist=資料夾:%n%n%1%n%n 不存在。要建立該資料夾嗎?
|
||||
|
||||
; *** "Select Components" wizard page
|
||||
WizardSelectComponents=選取元件
|
||||
SelectComponentsDesc=應安裝哪些元件?
|
||||
SelectComponentsLabel2=選取您要安裝的元件; 清除您不要安裝的元件。當您準備好要繼續時,請按一下 [下一步]。
|
||||
FullInstallation=完整安裝
|
||||
WizardSelectComponents=選擇元件
|
||||
SelectComponentsDesc=選擇將會被安裝的元件。
|
||||
SelectComponentsLabel2=選擇您想要安裝的元件;清除您不想安裝的元件。然後按 [下一步] 繼續安裝。
|
||||
FullInstallation=完整安裝
|
||||
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||
CompactInstallation=精簡安裝
|
||||
CustomInstallation=自訂安裝
|
||||
NoUninstallWarningTitle=已有此元件
|
||||
NoUninstallWarning=安裝程式偵測到您的電腦已安裝了下列元件:%n%n%1%n%n將這些元件取消選取並不會使元件解除安裝。%n%n仍要繼續嗎?
|
||||
CompactInstallation=最小安裝
|
||||
CustomInstallation=自訂安裝
|
||||
NoUninstallWarningTitle=元件已存在
|
||||
NoUninstallWarning=安裝程式偵測到以下元件已經安裝在您的電腦上:%n%n%1%n%n取消選擇這些元件將不會移除它們。%n%n您仍然要繼續嗎?
|
||||
ComponentSize1=%1 KB
|
||||
ComponentSize2=%1 MB
|
||||
ComponentsDiskSpaceMBLabel=目前的選擇至少需要 [mb] MB 的磁碟空間。
|
||||
ComponentsDiskSpaceMBLabel=目前的選擇需要至少 [mb] MB 磁碟空間。
|
||||
|
||||
; *** "Select Additional Tasks" wizard page
|
||||
WizardSelectTasks=選取其他工作
|
||||
SelectTasksDesc=還須執行哪些其他工作?
|
||||
SelectTasksLabel2=請選取安裝程式在安裝 [name] 時,須額外執行的其他工作,然後按一下 [下一步]。
|
||||
WizardSelectTasks=選擇附加的工作
|
||||
SelectTasksDesc=選擇要執行的附加工作。
|
||||
SelectTasksLabel2=選擇安裝程式在安裝 [name] 時要執行的附加工作,然後按 [下一步]。
|
||||
|
||||
; *** "Select Start Menu Folder" wizard page
|
||||
WizardSelectProgramGroup=選取 [開始] 功能表資料夾
|
||||
SelectStartMenuFolderDesc=安裝程式應將程式捷徑置於何處?
|
||||
SelectStartMenuFolderLabel3=安裝程式將在下列 [開始] 功能表資料夾中建立程式捷徑。
|
||||
SelectStartMenuFolderBrowseLabel=若要繼續,請按一下 [下一步]。若您想選取不同的資料夾,請按一下 [瀏覽]。
|
||||
MustEnterGroupName=必須輸入資料夾名稱。
|
||||
GroupNameTooLong=資料夾名稱或路徑過長。
|
||||
InvalidGroupName=此資料夾名稱無效。
|
||||
BadGroupName=資料夾名稱不得包含下列任一字元:%n%n%1
|
||||
NoProgramGroupCheck2=不要建立 [開始] 功能表資料夾(&D)
|
||||
WizardSelectProgramGroup=選擇「開始」功能表的資料夾
|
||||
SelectStartMenuFolderDesc=選擇安裝程式建立程式的捷徑的位置。
|
||||
SelectStartMenuFolderLabel3=安裝程式將會把程式的捷徑建立在下面的「開始」功能表資料夾。
|
||||
SelectStartMenuFolderBrowseLabel=按 [下一步] 繼續,如果您想選擇另一個資料夾,請按 [瀏覽]。
|
||||
MustEnterGroupName=您必須輸入一個資料夾的名稱。
|
||||
GroupNameTooLong=資料夾名稱或路徑太長。
|
||||
InvalidGroupName=資料夾名稱不正確。
|
||||
BadGroupName=資料夾名稱不得包含下列字元:%n%n%1
|
||||
NoProgramGroupCheck2=不要在「開始」功能表中建立資料夾(&D)
|
||||
|
||||
; *** "Ready to Install" wizard page
|
||||
WizardReady=已可開始安裝
|
||||
ReadyLabel1=安裝程式現在已可開始將 [name] 安裝到您的電腦上。
|
||||
ReadyLabel2a=若要繼續安裝,請按一下 [安裝]; 若要檢閱或變更任何設定,請按一下 [上一步]。
|
||||
ReadyLabel2b=若要繼續安裝,請按一下 [安裝]。
|
||||
ReadyMemoUserInfo=使用者資訊:
|
||||
ReadyMemoDir=目的地位置:
|
||||
ReadyMemoType=安裝類型:
|
||||
ReadyMemoComponents=選取的元件:
|
||||
ReadyMemoGroup=[開始] 功能表資料夾:
|
||||
ReadyMemoTasks=其他工作:
|
||||
WizardReady=準備安裝
|
||||
ReadyLabel1=安裝程式將開始安裝 [name] 到您的電腦中。
|
||||
ReadyLabel2a=按下 [安裝] 繼續安裝,或按 [上一步] 重新檢視或設定各選項的內容。
|
||||
ReadyLabel2b=按下 [安裝] 繼續安裝。
|
||||
ReadyMemoUserInfo=使用者資訊
|
||||
ReadyMemoDir=目的資料夾:
|
||||
ReadyMemoType=安裝型態:
|
||||
ReadyMemoComponents=選擇的元件:
|
||||
ReadyMemoGroup=「開始」功能表資料夾:
|
||||
ReadyMemoTasks=附加工作:
|
||||
|
||||
; *** "Preparing to Install" wizard page
|
||||
WizardPreparing=正在準備安裝
|
||||
PreparingDesc=安裝程式正在準備將 [name] 安裝到您的電腦上。
|
||||
PreviousInstallNotCompleted=上一個程式的安裝/移除尚未完成。必須重新啟動電腦,才能完成該安裝。%n%n請在重新啟動電腦之後,重新執行安裝程式,以完成 [name] 的安裝。
|
||||
CannotContinue=安裝程式無法繼續。請按一下 [取消] 以結束。
|
||||
ApplicationsFound=安裝程式必須更新下列應用程式正在使用的一些檔案。建議您允許安裝程式自動關閉這些應用程式。
|
||||
ApplicationsFound2=安裝程式必須更新下列應用程式正在使用的一些檔案。建議您允許安裝程式自動關閉這些應用程式。當安裝完成之後,安裝程式將會嘗試重新啟動這些應用程式。
|
||||
CloseApplications=自動關閉應用程式(&A)
|
||||
DontCloseApplications=不要關閉應用程式(&D)
|
||||
ErrorCloseApplications=安裝程式無法自動關閉所有應用程式。建議您關閉所有正在使用安裝程式必須更新之檔案的應用程式,然後再繼續。
|
||||
WizardPreparing=準備安裝程式
|
||||
PreparingDesc=安裝程式準備將 [name] 安裝到您的電腦上。
|
||||
PreviousInstallNotCompleted=先前的安裝/ 解除安裝尚未完成,您必須重新啟動電腦以完成該安裝。%n%n在重新啟動電腦之後,請再執行這個程式來安裝 [name]。
|
||||
CannotContinue=安裝程式無法繼續。請按 [取消] 離開。
|
||||
ApplicationsFound=下面的應用程式正在使用安裝程式所需要更新的文檔。建議您允許安裝程式自動關閉這些應用程式。
|
||||
ApplicationsFound2=下面的應用程式正在使用安裝程式所需要更新的文檔。建議您允許安裝程式自動關閉這些應用程式。當安裝過程結束後,本安裝程式將會嘗試重新開啟該應用程式。
|
||||
CloseApplications=關閉應用程式(&A)
|
||||
DontCloseApplications=不要關閉應用程式 (&D)
|
||||
ErrorCloseApplications=安裝程式無法自動關閉所有應用程式。建議您在繼續前先關閉所有應用程式使用的檔案。
|
||||
|
||||
; *** "Installing" wizard page
|
||||
WizardInstalling=安裝中
|
||||
InstallingLabel=請稍候,安裝程式正在將 [name] 安裝到您的電腦上。
|
||||
WizardInstalling=正在安裝
|
||||
InstallingLabel=請稍候,安裝程式正在將 [name] 安裝到您的電腦上
|
||||
|
||||
; *** "Setup Completed" wizard page
|
||||
FinishedHeadingLabel=正在完成 [name] 安裝精靈
|
||||
FinishedLabelNoIcons=安裝程式已完成您電腦上 [name] 的安裝。
|
||||
FinishedLabel=安裝程式已完成您電腦上 [name] 的安裝。您可以選取所安裝的捷徑來啟動應用程式。
|
||||
ClickFinish=請按一下 [完成],以結束安裝。
|
||||
FinishedRestartLabel=安裝程式必須重新啟動您的電腦,才能完成 [name] 的安裝。要立即重新啟動嗎?
|
||||
FinishedRestartMessage=安裝程式必須重新啟動您的電腦,才能完成 [name] 的安裝。%n%n要立即重新啟動嗎?
|
||||
ShowReadmeCheck=是,我要檢視讀我檔案
|
||||
YesRadio=是,立即重新啟動電腦(&Y)
|
||||
NoRadio=否,稍候再重新啟動電腦(&N)
|
||||
FinishedHeadingLabel=安裝完成
|
||||
FinishedLabelNoIcons=安裝程式已經將 [name] 安裝在您的電腦上。
|
||||
FinishedLabel=安裝程式已經將 [name] 安裝在您的電腦中,您可以選擇程式的圖示來執行該應用程式。
|
||||
ClickFinish=按 [完成] 以結束安裝程式。
|
||||
FinishedRestartLabel=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。您想要現在重新啟動電腦嗎?
|
||||
FinishedRestartMessage=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。%n%n您想要現在重新啟動電腦嗎?
|
||||
ShowReadmeCheck=是,我要閱讀讀我檔案。
|
||||
YesRadio=是,立即重新啟動電腦(&Y)
|
||||
NoRadio=否,我稍後重新啟動電腦(&N)
|
||||
; used for example as 'Run MyProg.exe'
|
||||
RunEntryExec=執行 %1
|
||||
RunEntryExec=執行 %1
|
||||
; used for example as 'View Readme.txt'
|
||||
RunEntryShellExec=檢視 %1
|
||||
; *** "Setup Needs the Next Disk" stuff
|
||||
ChangeDiskTitle=安裝程式需要下一張磁片。
|
||||
SelectDiskLabel2=請插入磁片 %1,然後按一下 [確定]。%n%n若此磁片上的檔案可以在下列顯示之資料夾以外的資料夾中找到,請輸入正確的路徑,或按一下 [瀏覽]。
|
||||
PathLabel=路徑(&P):
|
||||
FileNotInDir2=在 "%2" 中找不到檔案 "%1"。請插入正確的磁片,或選取其他資料夾。
|
||||
SelectDirectoryLabel=請指定下一張磁片的位置。
|
||||
RunEntryShellExec=檢視 %1
|
||||
|
||||
; *** "Setup Needs the Next Disk"
|
||||
ChangeDiskTitle=安裝程式需要下一張磁片
|
||||
SelectDiskLabel2=請插入磁片 %1,然後按 [確定]。%n%n如果檔案不在以下所顯示的資料夾之中,請輸入正確的資料夾名稱或按 [瀏覽] 選取。
|
||||
PathLabel=路徑(&P):
|
||||
FileNotInDir2=檔案“%1”無法在“%2”找到。請插入正確的磁片或選擇其它的資料夾。
|
||||
SelectDirectoryLabel=請指定下一張磁片的位置。
|
||||
|
||||
; *** Installation phase messages
|
||||
SetupAborted=安裝未安成。%n%n請修正問題,再重新執行安裝程式。
|
||||
EntryAbortRetryIgnore=若要再試一次,請按一下 [重試]; 若要繼續,請按一下 [忽略]; 若要取消安裝,請按一下 [中止]。
|
||||
SetupAborted=安裝沒有完成。%n%n請更正問題後重新安裝一次。
|
||||
AbortRetryIgnoreSelectAction=選取動作
|
||||
AbortRetryIgnoreRetry=請再試一次 (&T)
|
||||
AbortRetryIgnoreIgnore=略過錯誤並繼續 (&I)
|
||||
AbortRetryIgnoreCancel=取消安裝
|
||||
|
||||
; *** Installation status messages
|
||||
StatusClosingApplications=正在關閉應用程式...
|
||||
StatusCreateDirs=正在建立目錄...
|
||||
StatusExtractFiles=正在解壓縮檔案...
|
||||
StatusCreateIcons=正在建立捷徑...
|
||||
StatusCreateIniEntries=正在建立 INI 項目...
|
||||
StatusCreateRegistryEntries=正在建立登錄項目...
|
||||
StatusRegisterFiles=正在登錄檔案...
|
||||
StatusSavingUninstall=正在儲存解除安裝資訊...
|
||||
StatusRunProgram=正在完成安裝...
|
||||
StatusRestartingApplications=正在重新啟動應用程式...
|
||||
StatusRollback=正在復原變更...
|
||||
StatusClosingApplications=正在關閉應用程式...
|
||||
StatusCreateDirs=正在建立資料夾...
|
||||
StatusExtractFiles=正在解壓縮檔案...
|
||||
StatusCreateIcons=正在建立程式集圖示...
|
||||
StatusCreateIniEntries=寫入 INI 檔案的項目...
|
||||
StatusCreateRegistryEntries=正在更新系統登錄...
|
||||
StatusRegisterFiles=正在登錄檔案...
|
||||
StatusSavingUninstall=儲存解除安裝資訊...
|
||||
StatusRunProgram=正在完成安裝...
|
||||
StatusRestartingApplications=正在重新開啟應用程式...
|
||||
StatusRollback=正在復原變更...
|
||||
|
||||
; *** Misc. errors
|
||||
ErrorInternal2=內部錯誤: %1
|
||||
ErrorFunctionFailedNoCode=%1 失敗
|
||||
ErrorFunctionFailed=%1 失敗; 代碼 %2
|
||||
ErrorFunctionFailedWithMessage=%1 失敗; 代碼 %2。%n%3
|
||||
ErrorExecutingProgram=無法執行檔案:%n%1
|
||||
ErrorInternal2=內部錯誤: %1
|
||||
ErrorFunctionFailedNoCode=%1 失敗
|
||||
ErrorFunctionFailed=%1 失敗;代碼 %2
|
||||
ErrorFunctionFailedWithMessage=%1 失敗;代碼 %2.%n%3
|
||||
ErrorExecutingProgram=無法執行檔案:%n%1
|
||||
|
||||
; *** Registry errors
|
||||
ErrorRegOpenKey=開啟登錄機碼時發生錯誤:%n%1\%2
|
||||
ErrorRegCreateKey=建立登錄機碼時發生錯誤:%n%1\%2
|
||||
ErrorRegWriteKey=寫入登錄機碼時發生錯誤:%n%1\%2
|
||||
ErrorRegOpenKey=無法開啟登錄鍵:%n%1\%2
|
||||
ErrorRegCreateKey=無法建立登錄項目:%n%1\%2
|
||||
ErrorRegWriteKey=無法變更登錄項目:%n%1\%2
|
||||
|
||||
; *** INI errors
|
||||
ErrorIniEntry=在檔案 "%1" 中建立 INI 項目時發生錯誤。
|
||||
ErrorIniEntry=在檔案“%1”建立 INI 項目錯誤。
|
||||
|
||||
; *** File copying errors
|
||||
FileAbortRetryIgnore=若要再試一次,請按一下 [重試]; 若要略過此檔案,請按一下 [忽略] (不建議使用); 若要取消安裝,請按一下 [中止]。
|
||||
FileAbortRetryIgnore2=若要再試一次,請按一下 [重試]; 若要繼續,請按一下 [忽略] (不建議使用); 若要取消安裝,請按一下 [中止]。
|
||||
SourceIsCorrupted=原始程式檔已損毀
|
||||
SourceDoesntExist=原始程式檔 "%1" 不存在
|
||||
ExistingFileReadOnly=現有檔案已標記為唯讀。%n%n若要移除唯讀屬性,然後再試一次,請按一下 [重試]; 若要略過此檔案,請按一下 [忽略]; 若要取消安裝,請按一下 [中止]。
|
||||
ErrorReadingExistingDest=嘗試讀取現有檔案時發生錯誤:
|
||||
FileExists=已有此檔案。%n%n要由安裝程式加以覆寫嗎?
|
||||
ExistingFileNewer=現有檔案較安裝程式嘗試安裝的檔案新。建議您保留現有檔案。%n%n要保留現有的檔案嗎?
|
||||
ErrorChangingAttr=嘗試變更現有檔案的屬性時發生錯誤:
|
||||
ErrorCreatingTemp=嘗試在目的地目錄中建立檔案時發生錯誤:
|
||||
ErrorReadingSource=嘗試讀取原始程式檔時發生錯誤:
|
||||
ErrorCopying=嘗試複製檔案時發生錯誤:
|
||||
ErrorReplacingExistingFile=嘗試取代現有檔案時發生錯誤:
|
||||
ErrorRestartReplace=RestartReplace 失敗:
|
||||
ErrorRenamingTemp=嘗試重新命名目的地目錄中的檔案時發生錯誤:
|
||||
ErrorRegisterServer=無法登錄 DLL/OCX: %1
|
||||
ErrorRegSvr32Failed=RegSvr32 失敗,結束代碼為 %1
|
||||
ErrorRegisterTypeLib=無法登錄類型程式庫: %1
|
||||
FileAbortRetryIgnoreSkipNotRecommended=略過這個檔案 (不建議) (&S)
|
||||
FileAbortRetryIgnoreIgnoreNotRecommended=略過錯誤並繼續 (不建議) (&I)
|
||||
SourceDoesntExist=來源檔案“%1”不存在。
|
||||
SourceIsCorrupted=來源檔案已經損毀。
|
||||
ExistingFileReadOnly2=無法取代現有檔案,因為檔案已標示為唯讀。
|
||||
ExistingFileReadOnlyRetry=移除唯讀屬性並重試 (&R)
|
||||
ExistingFileReadOnlyKeepExisting=保留現有檔案 (&K)
|
||||
ErrorReadingExistingDest=讀取一個已存在的檔案時發生錯誤:
|
||||
FileExists=檔案已經存在。%n%n 要讓安裝程式加以覆寫嗎?
|
||||
ExistingFileNewer=存在的檔案版本比較新,建議您保留目前已存在的檔案。%n%n您要保留目前已存在的檔案嗎?
|
||||
ErrorChangingAttr=在變更檔案屬性時發生錯誤:
|
||||
ErrorCreatingTemp=在目的資料夾中建立檔案時發生錯誤:
|
||||
ErrorReadingSource=讀取原始檔案時發生錯誤:
|
||||
ErrorCopying=復制檔案時發生錯誤:
|
||||
ErrorReplacingExistingFile=取代檔案時發生錯誤:
|
||||
ErrorRestartReplace=重新啟動電腦後取代檔案失敗:
|
||||
ErrorRenamingTemp=在目的資料夾變更檔案名稱時發生錯誤:
|
||||
ErrorRegisterServer=無法注冊 DLL/OCX 檔案: %1。
|
||||
ErrorRegSvr32Failed=RegSvr32 失敗;退出代碼 %1
|
||||
ErrorRegisterTypeLib=無法注冊類型庫: %1。
|
||||
|
||||
; *** Uninstall display name markings
|
||||
; used for example as 'My Program (32-bit)'
|
||||
UninstallDisplayNameMark=%1 (%2)
|
||||
; used for example as 'My Program (32-bit, All users)'
|
||||
UninstallDisplayNameMarks=%1 (%2, %3)
|
||||
UninstallDisplayNameMark32Bit=32-bit
|
||||
UninstallDisplayNameMark64Bit=64-bit
|
||||
UninstallDisplayNameMarkAllUsers=所有使用者
|
||||
UninstallDisplayNameMarkCurrentUser=目前使用者
|
||||
|
||||
; *** Post-installation errors
|
||||
ErrorOpeningReadme=嘗試開啟讀我檔案時發生錯誤。
|
||||
ErrorRestartingComputer=安裝程式無法重新啟動電腦。請手動執行此作業。
|
||||
ErrorOpeningReadme=開啟讀我檔案時發生錯誤。
|
||||
ErrorRestartingComputer=安裝程式無法重新啟動電腦,請以手動方式自行重新啟動電腦。
|
||||
|
||||
; *** Uninstaller messages
|
||||
UninstallNotFound=沒有檔案 "%1"。無法解除安裝。
|
||||
UninstallOpenError=無法開啟檔案 "%1"。無法解除安裝
|
||||
UninstallUnsupportedVer=此版解除安裝程式無法辨識解除安裝記錄檔 "%1" 的格式。無法解除安裝
|
||||
UninstallUnknownEntry=在解除安裝記錄中找到不明的項目 (%1)
|
||||
ConfirmUninstall=確定要完全移除 %1 及其所有元件嗎?
|
||||
UninstallOnlyOnWin64=只可在 64 位元 Windows 上解除安裝此安裝。
|
||||
OnlyAdminCanUninstall=只有具備系統管理權限的使用者,才能解除安裝此安裝。
|
||||
UninstallStatusLabel=正在從您的電腦移除 %1,請稍候。
|
||||
UninstalledAll=已成功從您的電腦移除 %1。
|
||||
UninstalledMost=解除安裝 %1 已完成。%n%n有部分項目無法移除。您可以手動加以移除。
|
||||
UninstalledAndNeedsRestart=若要完成 %1 的解除安裝,必須重新啟動您的電腦。%n%n要立即重新啟動嗎?
|
||||
UninstallDataCorrupted="%1" 檔案已損毀。無法解除安裝
|
||||
UninstallNotFound=檔案“%1”不存在,無法移除程式。
|
||||
UninstallOpenError=無法開啟檔案“%1”,無法移除程式。
|
||||
UninstallUnsupportedVer=這個版本的解除安裝程式無法辨識記錄檔 “%1” 之格式,無法解除安裝。
|
||||
UninstallUnknownEntry=解除安裝記錄檔中發現未知的記錄 (%1)。
|
||||
ConfirmUninstall=您確定要完全移除 %1 及其相關的檔案嗎?
|
||||
UninstallOnlyOnWin64=這個程式只能在 64 位元的 Windows 上解除安裝。
|
||||
OnlyAdminCanUninstall=這個程式要具備系統管理員權限的使用者方可解除安裝。
|
||||
UninstallStatusLabel=正在從您的電腦移除 %1 中,請稍候...
|
||||
UninstalledAll=%1 已經成功從您的電腦中移除。
|
||||
UninstalledMost=%1 解除安裝完成。%n%n某些檔案及元件無法移除,您可以自行刪除這些檔案。
|
||||
UninstalledAndNeedsRestart=要完成 %1 的解除安裝程序,您必須重新啟動電腦。%n%n您想要現在重新啟動電腦嗎?
|
||||
UninstallDataCorrupted=檔案“%1”已經損毀,無法解除安裝。
|
||||
|
||||
; *** Uninstallation phase messages
|
||||
ConfirmDeleteSharedFileTitle=要移除共用檔案嗎?
|
||||
ConfirmDeleteSharedFile2=系統指出已無任何程式在使用下列共用檔案。您要解除安裝,以移除此共用檔案嗎?%n%n如有任何程式仍在使用此檔案而將該檔案移除,這些程式可能無法正常運作。若不確定,請選擇 [否]。將檔案保留在系統上並不會造成任何不良影響。
|
||||
SharedFileNameLabel=檔案名稱:
|
||||
SharedFileLocationLabel=位置:
|
||||
WizardUninstalling=解除安裝狀態
|
||||
StatusUninstalling=正在解除安裝 %1...
|
||||
ConfirmDeleteSharedFileTitle=移除共用檔案
|
||||
ConfirmDeleteSharedFile2=系統顯示下列共用檔案已不再被任何程式所使用,您要移除這些檔案嗎?%n%n%1%n%n倘若您移除了以上檔案但仍有程式需要使用它們,將造成這些程式無法正常執行,因此您若無法確定請選擇 [否]。保留這些檔案在您的系統中不會造成任何損害。
|
||||
SharedFileNameLabel=檔案名稱:
|
||||
SharedFileLocationLabel=位置:
|
||||
WizardUninstalling=解除安裝狀態
|
||||
StatusUninstalling=正在解除安裝 %1...
|
||||
|
||||
; *** Shutdown block reasons
|
||||
ShutdownBlockReasonInstallingApp=正在安裝 %1。
|
||||
ShutdownBlockReasonUninstallingApp=正在解除安裝 %1。
|
||||
ShutdownBlockReasonInstallingApp=正在安裝 %1.
|
||||
ShutdownBlockReasonUninstallingApp=正在解除安裝 %1.
|
||||
|
||||
; The custom messages below aren't used by Setup itself, but if you make
|
||||
; use of them in your scripts, you'll want to translate them.
|
||||
|
||||
[CustomMessages]
|
||||
NameAndVersion=%1 版 %2
|
||||
AdditionalIcons=其他捷徑:
|
||||
CreateDesktopIcon=建立桌面捷徑(&D)
|
||||
CreateQuickLaunchIcon=建立快速啟動捷徑(&Q)
|
||||
ProgramOnTheWeb=Web 上的 %1
|
||||
UninstallProgram=解除安裝 %1
|
||||
LaunchProgram=啟動 %1
|
||||
AssocFileExtension=關聯 %1 與 %2 副檔名(&A)
|
||||
AssocingFileExtension=正在建立 %1 與 %2 副檔名的關聯…
|
||||
AutoStartProgramGroupDescription=啟動:
|
||||
AutoStartProgram=自動啟動 %1
|
||||
AddonHostProgramNotFound=在選取的資料夾中找不到 %1。%n%n仍要繼續嗎?
|
||||
|
||||
NameAndVersion=%1 版本 %2
|
||||
AdditionalIcons=附加圖示:
|
||||
CreateDesktopIcon=建立桌面圖示(&D)
|
||||
CreateQuickLaunchIcon=建立快速啟動圖示(&Q)
|
||||
ProgramOnTheWeb=%1 的網站
|
||||
UninstallProgram=解除安裝 %1
|
||||
LaunchProgram=啟動 %1
|
||||
AssocFileExtension=將 %1 與檔案副檔名 %2 產生關聯(&A)
|
||||
AssocingFileExtension=正在將 %1 與檔案副檔名 %2 產生關聯...
|
||||
AutoStartProgramGroupDescription=開啟:
|
||||
AutoStartProgram=自動開啟 %1
|
||||
AddonHostProgramNotFound=%1 無法在您所選的資料夾中找到。%n%n您是否還要繼續?
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
[Messages]
|
||||
FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed shortcuts.
|
||||
ConfirmUninstall=Are you sure you want to completely remove %1 and all of its components?
|
||||
|
||||
[CustomMessages]
|
||||
AdditionalIcons=Additional icons:
|
||||
CreateDesktopIcon=Create a &desktop icon
|
||||
CreateQuickLaunchIcon=Create a &Quick Launch icon
|
||||
AddContextMenuFiles=Add "Open with %1" action to Windows Explorer file context menu
|
||||
AddContextMenuFolders=Add "Open with %1" action to Windows Explorer directory context menu
|
||||
AssociateWithFiles=Register %1 as an editor for supported file types
|
||||
|
||||
@@ -1817,10 +1817,10 @@ https-proxy-agent@^4.0.0:
|
||||
agent-base "5"
|
||||
debug "4"
|
||||
|
||||
iconv-lite-umd@0.6.5:
|
||||
version "0.6.5"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.5.tgz#6a1f621a3b4d125f72feff813a9839e1ebd6c722"
|
||||
integrity sha512-WDegH4al+e3n3jTOStRvm+jzDA3JMUQGgzdAsMxAgcgB0Oi72HjfdsoX08ieKsy3rKexXVjWZr41aOIUaCZnMg==
|
||||
iconv-lite-umd@0.6.8:
|
||||
version "0.6.8"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.8.tgz#5ad310ec126b260621471a2d586f7f37b9958ec0"
|
||||
integrity sha512-zvXJ5gSwMC9JD3wDzH8CoZGc1pbiJn12Tqjk8BXYCnYz3hYL5GRjHW8LEykjXhV9WgNGI4rgpgHcbIiBfrRq6A==
|
||||
|
||||
iconv-lite@^0.4.4:
|
||||
version "0.4.24"
|
||||
@@ -2123,6 +2123,11 @@ json-stringify-safe@~5.0.1:
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
jsonc-parser@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.0.tgz#7c7fc988ee1486d35734faaaa866fadb00fa91ee"
|
||||
integrity sha512-b0EBt8SWFNnixVdvoR2ZtEGa9ZqLhbJnOjezn+WP+8kspFm+PFYDN8Z4Bc7pRlDjvuVcADSUkroIuTWWn/YiIA==
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
||||
@@ -2296,9 +2301,9 @@ lodash.unescape@4.0.1:
|
||||
integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=
|
||||
|
||||
lodash@^4.15.0, lodash@^4.17.10:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
macos-release@^2.2.0:
|
||||
version "2.3.0"
|
||||
@@ -3539,10 +3544,10 @@ typescript@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
||||
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
||||
|
||||
typescript@^4.0.0-dev.20200629:
|
||||
version "4.0.0-dev.20200629"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200629.tgz#4631667ebffe3a340beee885a4bebe3a73b6f18e"
|
||||
integrity sha512-c4DUu7KvTcx4x7V8sBWexYNkCfioiH1huOJL6WFAA8Oot0Gr/+PlKKDBS9fYjsadEv1JI1qboJKobwLQn0kQXw==
|
||||
typescript@^4.0.0-dev.20200803:
|
||||
version "4.0.0-dev.20200803"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200803.tgz#ea8b0e9fb2ee3085598ff200c8568f04f4cbb2ba"
|
||||
integrity sha512-f/jDkFqCs0gbUd5MCUijO9u3AOMx1x1HdRDDHSidlc6uPVEkRduxjeTFhIXbGutO7ivzv+aC2sxH+1FQwsyBcg==
|
||||
|
||||
typical@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@@ -330,5 +330,34 @@
|
||||
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
|
||||
"SOFTWARE."
|
||||
]
|
||||
},
|
||||
{
|
||||
// Reason: The license at https://github.com/colorjs/color-name/blob/master/LICENSE
|
||||
// cannot be found by the OSS tool automatically.
|
||||
"name": "color-name",
|
||||
"fullLicenseText": [
|
||||
"The MIT License (MIT)",
|
||||
"Copyright (c) 2015 Dmitry Ivanov",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:",
|
||||
"",
|
||||
"The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.",
|
||||
"",
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
||||
]
|
||||
},
|
||||
{
|
||||
// Reason: The license cannot be found by the tool due to access controls on the repository
|
||||
"name": "tas-client",
|
||||
"fullLicenseText": [
|
||||
"MIT License",
|
||||
"Copyright (c) 2020 - present Microsoft Corporation",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:",
|
||||
"",
|
||||
"The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.",
|
||||
"",
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -533,7 +533,7 @@
|
||||
"git": {
|
||||
"name": "ripgrep",
|
||||
"repositoryUrl": "https://github.com/BurntSushi/ripgrep",
|
||||
"commitHash": "8a7db1a918e969b85cd933d8ed9fa5285b281ba4"
|
||||
"commitHash": "973de50c9ef451da2cfcdfa86f2b2711d8d6ff48"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
|
||||
@@ -67,6 +67,23 @@
|
||||
"when": "isWindows && connectionProvider == MSSQL && serverInfo && nodeType && mssql:engineedition != 11 && nodeType =~ /^(Database|Table|Column|Index|Statistic|View|ServerLevelLogin|ServerLevelServerRole|ServerLevelCredential|ServerLevelServerAudit|ServerLevelServerAuditSpecification|StoredProcedure|ScalarValuedFunction|TableValuedFunction|AggregateFunction|Synonym|Assembly|UserDefinedDataType|UserDefinedType|UserDefinedTableType|Sequence|User|DatabaseRole|ApplicationRole|Schema|SecurityPolicy|ServerLevelLinkedServer)$/",
|
||||
"group": "z-AdminToolExt@2"
|
||||
}
|
||||
],
|
||||
"dataExplorer/context": [
|
||||
{
|
||||
"command": "adminToolExtWin.launchSsmsMinGswDialog",
|
||||
"when": "isWindows && connectionProvider == MSSQL && nodeType && nodeType == Database && mssql:engineedition != 11",
|
||||
"group": "z-AdminToolExt@1"
|
||||
},
|
||||
{
|
||||
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog",
|
||||
"when": "isWindows && connectionProvider == MSSQL && !isCloud && nodeType && nodeType == Server && mssql:engineedition != 11",
|
||||
"group": "z-AdminToolExt@2"
|
||||
},
|
||||
{
|
||||
"command": "adminToolExtWin.launchSsmsMinPropertiesDialog",
|
||||
"when": "isWindows && connectionProvider == MSSQL && nodeType && mssql:engineedition != 11 && nodeType =~ /^(Database|Table|Column|Index|Statistic|View|ServerLevelLogin|ServerLevelServerRole|ServerLevelCredential|ServerLevelServerAudit|ServerLevelServerAuditSpecification|StoredProcedure|ScalarValuedFunction|TableValuedFunction|AggregateFunction|Synonym|Assembly|UserDefinedDataType|UserDefinedType|UserDefinedTableType|Sequence|User|DatabaseRole|ApplicationRole|Schema|SecurityPolicy|ServerLevelLinkedServer)$/",
|
||||
"group": "z-AdminToolExt@2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outputChannels": [
|
||||
|
||||
@@ -643,9 +643,9 @@ json5@^2.1.2:
|
||||
minimist "^1.2.5"
|
||||
|
||||
lodash@^4.16.4, lodash@^4.17.13:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
make-dir@^2.1.0:
|
||||
version "2.1.0"
|
||||
|
||||
@@ -509,9 +509,9 @@ json5@^2.1.2:
|
||||
minimist "^1.2.5"
|
||||
|
||||
lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
make-dir@^2.1.0:
|
||||
version "2.1.0"
|
||||
|
||||
@@ -247,4 +247,4 @@
|
||||
"execution_count": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### **Ensure PostgreSQL server group name, subscription id and resource group name**"
|
||||
"#### **Get required and optional parameters for the PostgreSQL server group**"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "68ec0760-27d1-4ded-9a9f-89077c40b8bb"
|
||||
@@ -85,8 +85,6 @@
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"# Required Values\n",
|
||||
"subscription = os.environ[\"AZDATA_NB_VAR_ARC_SUBSCRIPTION\"]\n",
|
||||
"resource_group_name = os.environ[\"AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME\"]\n",
|
||||
"server_group_name = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAME\"]\n",
|
||||
"server_group_namespace = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_NAMESPACE\"]\n",
|
||||
"server_group_workers = os.environ[\"AZDATA_NB_VAR_POSTGRES_SERVER_GROUP_WORKERS\"]\n",
|
||||
@@ -142,7 +140,7 @@
|
||||
"backup_delta_interval_option = f' --deltaBackupInterval \"{server_group_backup_delta_interval}\"' if server_group_backup_delta_interval else \"\"\n",
|
||||
"backup_retention_min_option = f' --retentionMin \"{server_group_backup_retention_min}\"' if server_group_backup_retention_min else \"\"\n",
|
||||
"backup_retention_max_option = f' --retentionMax \"{server_group_backup_retention_max}\"' if server_group_backup_retention_max else \"\"\n",
|
||||
"cmd = f'azdata postgres server create --subscription {subscription} --rg {resource_group_name} --name {server_group_name} --namespace {server_group_namespace} --workers {server_group_workers} --serviceType {server_group_service_type} --dataSizeMb {server_group_data_size}{data_class_option}{port_option}{extensions_option}{cpu_min_option}{cpu_max_option}{memory_min_option}{memory_max_option}{backup_classes_option}{backup_sizes_option}{backup_full_interval_option}{backup_delta_interval_option}{backup_retention_min_option}{backup_retention_max_option}'\n",
|
||||
"cmd = f'azdata postgres server create --name {server_group_name} --namespace {server_group_namespace} --workers {server_group_workers} --serviceType {server_group_service_type} --dataSizeMb {server_group_data_size}{data_class_option}{port_option}{extensions_option}{cpu_min_option}{cpu_max_option}{memory_min_option}{memory_max_option}{backup_classes_option}{backup_sizes_option}{backup_full_interval_option}{backup_delta_interval_option}{backup_retention_min_option}{backup_retention_max_option}'\n",
|
||||
"out=run_command()"
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "arc",
|
||||
"displayName": "%arc.displayName%",
|
||||
"description": "%arc.description%",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||
@@ -712,17 +712,6 @@
|
||||
{
|
||||
"title": "",
|
||||
"sections": [
|
||||
{
|
||||
"title": "%arc.azure.section.title%",
|
||||
"fields": [
|
||||
{
|
||||
"subscriptionVariableName": "AZDATA_NB_VAR_ARC_SUBSCRIPTION",
|
||||
"resourceGroupVariableName": "AZDATA_NB_VAR_ARC_RESOURCE_GROUP_NAME",
|
||||
"type": "azure_account",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "%arc.postgres.settings.section.title%",
|
||||
"fields": [
|
||||
@@ -926,10 +915,12 @@
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/request": "^2.48.3",
|
||||
"@types/sinon": "^9.0.4",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"should": "^13.2.3",
|
||||
"sinon": "^9.0.2",
|
||||
"typemoq": "2.1.0",
|
||||
"vscodetestcover": "^1.0.9"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as azurecore from '../../../azurecore/src/azurecore';
|
||||
import * as loc from '../localizedConstants';
|
||||
import { IconPathHelper, IconPath, ResourceType, Connectionmode } from '../constants';
|
||||
import { IconPathHelper, IconPath, ResourceType, ConnectionMode } from '../constants';
|
||||
|
||||
export class UserCancelledError extends Error { }
|
||||
|
||||
@@ -71,10 +71,10 @@ export function getResourceTypeIcon(resourceType: string | undefined): IconPath
|
||||
export function getConnectionModeDisplayText(connectionMode: string | undefined): string {
|
||||
connectionMode = connectionMode ?? '';
|
||||
switch (connectionMode) {
|
||||
case Connectionmode.connected:
|
||||
return loc.connected;
|
||||
case Connectionmode.disconnected:
|
||||
return loc.disconnected;
|
||||
case ConnectionMode.direct:
|
||||
return loc.direct;
|
||||
case ConnectionMode.indirect:
|
||||
return loc.indirect;
|
||||
}
|
||||
return connectionMode;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export function getDatabaseStateDisplayText(state: string): string {
|
||||
case 'SUSPECT':
|
||||
return loc.suspect;
|
||||
case 'EMERGENCY':
|
||||
return loc.emergecy;
|
||||
return loc.emergency;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -131,9 +131,9 @@ export const enum Endpoints {
|
||||
controller = 'controller'
|
||||
}
|
||||
|
||||
export const enum Connectionmode {
|
||||
connected = 'connected',
|
||||
disconnected = 'disconnected'
|
||||
export const enum ConnectionMode {
|
||||
direct = 'direct',
|
||||
indirect = 'indirect'
|
||||
}
|
||||
|
||||
export namespace cssStyles {
|
||||
|
||||
@@ -68,12 +68,14 @@ export const running = localize('arc.running', "Running");
|
||||
export const pending = localize('arc.pending', "Pending");
|
||||
export const failed = localize('arc.failed', "Failed");
|
||||
export const unknown = localize('arc.unknown', "Unknown");
|
||||
export const connected = localize('arc.connected', "Connected");
|
||||
export const disconnected = localize('arc.disconnected', "Disconnected");
|
||||
export const direct = localize('arc.direct', "Direct");
|
||||
export const indirect = localize('arc.indirect', "Indirect");
|
||||
export const loading = localize('arc.loading', "Loading...");
|
||||
export const refreshToEnterCredentials = localize('arc.refreshToEnterCredentials', "Refresh node to enter credentials");
|
||||
export const connectToController = localize('arc.connectToController', "Connect to Existing Controller");
|
||||
export const controllerUrl = localize('arc.controllerUrl', "Controller URL");
|
||||
export const controllerName = localize('arc.controllerName', "Name");
|
||||
export const defaultControllerName = localize('arc.defaultControllerName', "arc-dc");
|
||||
export const username = localize('arc.username', "Username");
|
||||
export const password = localize('arc.password', "Password");
|
||||
export const rememberPassword = localize('arc.rememberPassword', "Remember Password");
|
||||
@@ -87,7 +89,7 @@ export const restoring = localize('arc.restoring', "Restoring");
|
||||
export const recovering = localize('arc.recovering', "Recovering");
|
||||
export const recoveryPending = localize('arc.recoveringPending', "Recovery Pending");
|
||||
export const suspect = localize('arc.suspect', "Suspect");
|
||||
export const emergecy = localize('arc.emergecy', "Emergecy");
|
||||
export const emergency = localize('arc.emergency', "Emergency");
|
||||
|
||||
// Postgres constants
|
||||
export const coordinatorEndpoint = localize('arc.coordinatorEndpoint', "Coordinator endpoint");
|
||||
@@ -142,9 +144,9 @@ export function openDashboardFailed(error: any): string { return localize('arc.o
|
||||
export function resourceDeletionFailed(name: string, error: any): string { return localize('arc.resourceDeletionFailed', "Failed to delete resource {0}. {1}", name, getErrorMessage(error)); }
|
||||
export function databaseCreationFailed(name: string, error: any): string { return localize('arc.databaseCreationFailed', "Failed to create database {0}. {1}", name, getErrorMessage(error)); }
|
||||
export function connectToControllerFailed(url: string, error: any): string { return localize('arc.connectToControllerFailed', "Could not connect to controller {0}. {1}", url, getErrorMessage(error)); }
|
||||
export function fetchStatusFailed(name: string, error: any): string { return localize('arc.fetchStatusFailed', "An unexpected error occured retrieving the status for resource '{0}'. {1}", name, getErrorMessage(error)); }
|
||||
export function fetchEndpointsFailed(name: string, error: any): string { return localize('arc.fetchEndpointsFailed', "An unexpected error occured retrieving the endpoints for '{0}'. {1}", name, getErrorMessage(error)); }
|
||||
export function fetchRegistrationsFailed(name: string, error: any): string { return localize('arc.fetchRegistrationsFailed', "An unexpected error occured retrieving the registrations for '{0}'. {1}", name, getErrorMessage(error)); }
|
||||
export function fetchStatusFailed(name: string, error: any): string { return localize('arc.fetchStatusFailed', "An unexpected error occurred retrieving the status for resource '{0}'. {1}", name, getErrorMessage(error)); }
|
||||
export function fetchEndpointsFailed(name: string, error: any): string { return localize('arc.fetchEndpointsFailed', "An unexpected error occurred retrieving the endpoints for '{0}'. {1}", name, getErrorMessage(error)); }
|
||||
export function fetchRegistrationsFailed(name: string, error: any): string { return localize('arc.fetchRegistrationsFailed', "An unexpected error occurred retrieving the registrations for '{0}'. {1}", name, getErrorMessage(error)); }
|
||||
export function couldNotFindRegistration(namespace: string, name: string) { return localize('arc.couldNotFindRegistration', "Could not find controller registration for {0} ({1})", name, namespace); }
|
||||
export function resourceDeletionWarning(namespace: string, name: string): string { return localize('arc.resourceDeletionWarning', "Warning! Deleting a resource is permanent and cannot be undone. To delete the resource '{0}.{1}' type the name '{1}' below to proceed.", namespace, name); }
|
||||
export function invalidResourceDeletionName(name: string): string { return localize('arc.invalidResourceDeletionName', "The value '{0}' does not match the instance name. Try again or press escape to exit", name); }
|
||||
|
||||
@@ -14,6 +14,7 @@ import * as loc from '../localizedConstants';
|
||||
|
||||
export type ControllerInfo = {
|
||||
url: string,
|
||||
name: string,
|
||||
username: string,
|
||||
rememberPassword: boolean,
|
||||
resources: ResourceInfo[]
|
||||
@@ -74,7 +75,7 @@ export class ControllerModel {
|
||||
if (password && !promptReconnect) {
|
||||
this.setAuthentication(new BasicAuth(this.info.username, password));
|
||||
} else {
|
||||
// No password yet or we want to reprompt for credentials so prompt for it from the user
|
||||
// No password yet or we want to re-prompt for credentials so prompt for it from the user
|
||||
const dialog = new ConnectToControllerDialog(this.treeDataProvider);
|
||||
dialog.showDialog(this.info, password);
|
||||
const model = await dialog.waitForClose();
|
||||
@@ -182,6 +183,13 @@ export class ControllerModel {
|
||||
this._registrationRouter.setDefaultAuthentication(auth);
|
||||
this._sqlInstanceRouter.setDefaultAuthentication(auth);
|
||||
}
|
||||
|
||||
/**
|
||||
* property to for use a display label for this controller
|
||||
*/
|
||||
public get label(): string {
|
||||
return `${this.info.name} (${this.info.url})`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'mocha';
|
||||
import { resourceTypeToDisplayName, parseEndpoint, parseInstanceName, getAzurecoreApi, getResourceTypeIcon, getConnectionModeDisplayText, getDatabaseStateDisplayText, promptForResourceDeletion, promptAndConfirmPassword, getErrorMessage } from '../../common/utils';
|
||||
|
||||
import * as loc from '../../localizedConstants';
|
||||
import { ResourceType, IconPathHelper, Connectionmode as ConnectionMode } from '../../constants';
|
||||
import { ResourceType, IconPathHelper, ConnectionMode as ConnectionMode } from '../../constants';
|
||||
import { MockInputBox } from '../stubs';
|
||||
import { HttpError } from '../../controller/generated/v1/api';
|
||||
import { IncomingMessage } from 'http';
|
||||
@@ -91,8 +91,8 @@ describe('getResourceTypeIcon Method Tests', function () {
|
||||
|
||||
describe('getConnectionModeDisplayText Method Tests', function () {
|
||||
it('Display Name should be correct for valid ResourceType', function (): void {
|
||||
should(getConnectionModeDisplayText(ConnectionMode.connected)).equal(loc.connected);
|
||||
should(getConnectionModeDisplayText(ConnectionMode.disconnected)).equal(loc.disconnected);
|
||||
should(getConnectionModeDisplayText(ConnectionMode.direct)).equal(loc.direct);
|
||||
should(getConnectionModeDisplayText(ConnectionMode.indirect)).equal(loc.indirect);
|
||||
});
|
||||
|
||||
it('Display Name should be correct for unknown value', function (): void {
|
||||
@@ -116,7 +116,7 @@ describe('getDatabaseStateDisplayText Method Tests', function () {
|
||||
should(getDatabaseStateDisplayText('RECOVERING')).equal(loc.recovering);
|
||||
should(getDatabaseStateDisplayText('RECOVERY PENDING')).equal(loc.recoveryPending);
|
||||
should(getDatabaseStateDisplayText('SUSPECT')).equal(loc.suspect);
|
||||
should(getDatabaseStateDisplayText('EMERGENCY')).equal(loc.emergecy);
|
||||
should(getDatabaseStateDisplayText('EMERGENCY')).equal(loc.emergency);
|
||||
});
|
||||
|
||||
it('State should stay the same for unknown value', function (): void {
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import { ControllerInfo, ControllerModel, Registration } from '../../../models/controllerModel';
|
||||
import { ConnectToControllerDialog } from '../../../ui/dialogs/connectControllerDialog';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
|
||||
describe('ConnectControllerDialog', function (): void {
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
(<{ info: ControllerInfo | undefined, description: string }[]>[
|
||||
{ info: undefined, description: 'all input' },
|
||||
{ info: { url: '127.0.0.1' }, description: 'all but URL' },
|
||||
{ info: { url: '127.0.0.1', username: 'sa' }, description: 'all but URL and password' }]).forEach(test => {
|
||||
it(`Validate returns false when ${test.description} is empty`, async function (): Promise<void> {
|
||||
const connectControllerDialog = new ConnectToControllerDialog(undefined!);
|
||||
connectControllerDialog.showDialog(test.info, undefined);
|
||||
await connectControllerDialog.isInitialized;
|
||||
const validateResult = await connectControllerDialog.validate();
|
||||
should(validateResult).be.false();
|
||||
});
|
||||
});
|
||||
|
||||
it('validate returns false if controller refresh fails', async function (): Promise<void> {
|
||||
sinon.stub(ControllerModel.prototype, 'refresh').returns(Promise.reject('Controller refresh failed'));
|
||||
const connectControllerDialog = new ConnectToControllerDialog(undefined!);
|
||||
const info = { url: 'https://127.0.0.1:30080', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] };
|
||||
connectControllerDialog.showDialog(info, 'pwd');
|
||||
await connectControllerDialog.isInitialized;
|
||||
const validateResult = await connectControllerDialog.validate();
|
||||
should(validateResult).be.false('Validation should have returned false');
|
||||
});
|
||||
|
||||
it('validate replaces http with https', async function (): Promise<void> {
|
||||
await validateConnectControllerDialog(
|
||||
{ url: 'http://127.0.0.1:30081', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] },
|
||||
'https://127.0.0.1:30081');
|
||||
});
|
||||
|
||||
it('validate appends https if missing', async function (): Promise<void> {
|
||||
await validateConnectControllerDialog({ url: '127.0.0.1:30080', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] },
|
||||
'https://127.0.0.1:30080');
|
||||
});
|
||||
|
||||
it('validate appends default port if missing', async function (): Promise<void> {
|
||||
await validateConnectControllerDialog({ url: 'https://127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] },
|
||||
'https://127.0.0.1:30080');
|
||||
});
|
||||
|
||||
it('validate appends both port and https if missing', async function (): Promise<void> {
|
||||
await validateConnectControllerDialog({ url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] },
|
||||
'https://127.0.0.1:30080');
|
||||
});
|
||||
|
||||
for (const name of ['', undefined]) {
|
||||
it(`validate display name gets set to arc instance name for user chosen name of:${name}`, async function (): Promise<void> {
|
||||
await validateConnectControllerDialog(
|
||||
{ url: 'http://127.0.0.1:30081', name: name!, username: 'sa', rememberPassword: true, resources: [] },
|
||||
'https://127.0.0.1:30081');
|
||||
});
|
||||
}
|
||||
|
||||
it(`validate display name gets set to default data controller name for user chosen name of:'' and instanceName in explicably returned as undefined from the controller endpoint`, async function (): Promise<void> {
|
||||
await validateConnectControllerDialog(
|
||||
{ url: 'http://127.0.0.1:30081', name: '', username: 'sa', rememberPassword: true, resources: [] },
|
||||
'https://127.0.0.1:30081',
|
||||
undefined);
|
||||
});
|
||||
});
|
||||
|
||||
async function validateConnectControllerDialog(info: ControllerInfo, expectedUrl: string, arcInstanceName: string = 'arc-instance'): Promise<void> {
|
||||
const expectedControllerInfoName = info.name || arcInstanceName || loc.defaultControllerName;
|
||||
const connectControllerDialog = new ConnectToControllerDialog(undefined!);
|
||||
// Stub out refresh calls to controllerModel - we'll test those separately
|
||||
sinon.stub(ControllerModel.prototype, 'refresh').returns(Promise.resolve());
|
||||
// stub out controller registration response to return a known instanceName for the dc.
|
||||
sinon.stub(ControllerModel.prototype, 'controllerRegistration').get(() => {
|
||||
return <Registration>{ instanceName: arcInstanceName };
|
||||
});
|
||||
connectControllerDialog.showDialog(info, 'pwd');
|
||||
await connectControllerDialog.isInitialized;
|
||||
const validateResult = await connectControllerDialog.validate();
|
||||
should(validateResult).be.true('Validation should have returned true');
|
||||
const model = await connectControllerDialog.waitForClose();
|
||||
should(model?.controllerModel.info.url).equal(expectedUrl);
|
||||
should(model?.controllerModel.info.name).equal(expectedControllerInfoName);
|
||||
}
|
||||
@@ -3,12 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as should from 'should';
|
||||
import 'mocha';
|
||||
import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { AzureArcTreeDataProvider } from '../../../ui/tree/azureArcTreeDataProvider';
|
||||
import * as vscode from 'vscode';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { AzureArcTreeDataProvider } from '../../../ui/tree/azureArcTreeDataProvider';
|
||||
import { ControllerTreeNode } from '../../../ui/tree/controllerTreeNode';
|
||||
|
||||
describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
@@ -43,7 +43,7 @@ describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
treeDataProvider['_loading'] = false;
|
||||
let children = await treeDataProvider.getChildren();
|
||||
should(children.length).equal(0, 'There initially shouldn\'t be any children');
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { url: '127.0.0.1', username: 'sa', rememberPassword: true, resources: [] });
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] });
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
should(children.length).equal(1, 'Controller node should be added correctly');
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
@@ -54,11 +54,11 @@ describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
treeDataProvider['_loading'] = false;
|
||||
let children = await treeDataProvider.getChildren();
|
||||
should(children.length).equal(0, 'There initially shouldn\'t be any children');
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { url: '127.0.0.1', username: 'sa', rememberPassword: true, resources: [] });
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] });
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
should(children.length).equal(1, 'Controller node should be added correctly');
|
||||
should((<ControllerTreeNode>children[0]).model.info.rememberPassword).be.true('Info was not set correctly initially');
|
||||
const controllerModel2 = new ControllerModel(treeDataProvider, { url: '127.0.0.1', username: 'sa', rememberPassword: false, resources: [] });
|
||||
const controllerModel2 = new ControllerModel(treeDataProvider, { url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: false, resources: [] });
|
||||
await treeDataProvider.addOrUpdateController(controllerModel2, '');
|
||||
should(children.length).equal(1, 'Shouldn\'t add duplicate controller node');
|
||||
should((<ControllerTreeNode>children[0]).model.info.rememberPassword).be.false('Info was not updated correctly');
|
||||
@@ -82,8 +82,8 @@ describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
describe('removeController', function (): void {
|
||||
it('removing a controller should work as expected', async function (): Promise<void> {
|
||||
treeDataProvider['_loading'] = false;
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { url: '127.0.0.1', username: 'sa', rememberPassword: true, resources: [] });
|
||||
const controllerModel2 = new ControllerModel(treeDataProvider, { url: '127.0.0.2', username: 'cloudsa', rememberPassword: true, resources: [] });
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] });
|
||||
const controllerModel2 = new ControllerModel(treeDataProvider, { url: '127.0.0.2', name: 'my-arc', username: 'cloudsa', rememberPassword: true, resources: [] });
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
await treeDataProvider.addOrUpdateController(controllerModel2, '');
|
||||
const children = <ControllerTreeNode[]>(await treeDataProvider.getChildren());
|
||||
|
||||
@@ -17,6 +17,10 @@ export abstract class InitializingComponent {
|
||||
return this._initialized;
|
||||
}
|
||||
|
||||
public get isInitialized(): Promise<void> {
|
||||
return this.onInitializedPromise.promise;
|
||||
}
|
||||
|
||||
protected set initialized(value: boolean) {
|
||||
if (!this._initialized && value) {
|
||||
this._initialized = true;
|
||||
|
||||
@@ -31,7 +31,7 @@ export class PostgresOverviewPage extends DashboardPage {
|
||||
this.disposables.push(
|
||||
this._controllerModel.onEndpointsUpdated(() => this.eventuallyRunOnInitialized(() => this.handleEndpointsUpdated())),
|
||||
this._controllerModel.onRegistrationsUpdated(() => this.eventuallyRunOnInitialized(() => this.handleRegistrationsUpdated())),
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => this.hadleServiceUpdated())),
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => this.handleServiceUpdated())),
|
||||
this._postgresModel.onPodsUpdated(() => this.eventuallyRunOnInitialized(() => this.handlePodsUpdated())));
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ export class PostgresOverviewPage extends DashboardPage {
|
||||
this.propertiesLoading!.loading = false;
|
||||
}
|
||||
|
||||
private hadleServiceUpdated() {
|
||||
private handleServiceUpdated() {
|
||||
this.properties!.propertyItems = this.getProperties();
|
||||
this.propertiesLoading!.loading = false;
|
||||
|
||||
|
||||
@@ -5,26 +5,29 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as loc from '../../localizedConstants';
|
||||
import { AzureArcTreeDataProvider } from '../tree/azureArcTreeDataProvider';
|
||||
import { ControllerModel, ControllerInfo } from '../../models/controllerModel';
|
||||
import { Deferred } from '../../common/promise';
|
||||
import * as loc from '../../localizedConstants';
|
||||
import { ControllerInfo, ControllerModel } from '../../models/controllerModel';
|
||||
import { InitializingComponent } from '../components/initializingComponent';
|
||||
import { AzureArcTreeDataProvider } from '../tree/azureArcTreeDataProvider';
|
||||
|
||||
export type ConnectToControllerDialogModel = { controllerModel: ControllerModel, password: string };
|
||||
|
||||
export class ConnectToControllerDialog {
|
||||
export class ConnectToControllerDialog extends InitializingComponent {
|
||||
private modelBuilder!: azdata.ModelBuilder;
|
||||
|
||||
private urlInputBox!: azdata.InputBoxComponent;
|
||||
private nameInputBox!: azdata.InputBoxComponent;
|
||||
private usernameInputBox!: azdata.InputBoxComponent;
|
||||
private passwordInputBox!: azdata.InputBoxComponent;
|
||||
private rememberPwCheckBox!: azdata.CheckBoxComponent;
|
||||
|
||||
private _completionPromise = new Deferred<ConnectToControllerDialogModel | undefined>();
|
||||
|
||||
constructor(private _treeDataProvider: AzureArcTreeDataProvider) { }
|
||||
constructor(private _treeDataProvider: AzureArcTreeDataProvider) {
|
||||
super();
|
||||
}
|
||||
|
||||
public showDialog(controllerInfo?: ControllerInfo, password?: string): void {
|
||||
public showDialog(controllerInfo?: ControllerInfo, password?: string): azdata.window.Dialog {
|
||||
const dialog = azdata.window.createModelViewDialog(loc.connectToController);
|
||||
dialog.cancelButton.onClick(() => this.handleCancel());
|
||||
dialog.registerContent(async view => {
|
||||
@@ -36,6 +39,10 @@ export class ConnectToControllerDialog {
|
||||
// If we have a model then we're editing an existing connection so don't let them modify the URL
|
||||
readOnly: !!controllerInfo
|
||||
}).component();
|
||||
this.nameInputBox = this.modelBuilder.inputBox()
|
||||
.withProperties<azdata.InputBoxProperties>({
|
||||
value: controllerInfo?.name
|
||||
}).component();
|
||||
this.usernameInputBox = this.modelBuilder.inputBox()
|
||||
.withProperties<azdata.InputBoxProperties>({
|
||||
value: controllerInfo?.username
|
||||
@@ -59,6 +66,10 @@ export class ConnectToControllerDialog {
|
||||
component: this.urlInputBox,
|
||||
title: loc.controllerUrl,
|
||||
required: true
|
||||
}, {
|
||||
component: this.nameInputBox,
|
||||
title: loc.controllerName,
|
||||
required: false
|
||||
}, {
|
||||
component: this.usernameInputBox,
|
||||
title: loc.username,
|
||||
@@ -76,28 +87,46 @@ export class ConnectToControllerDialog {
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
await view.initializeModel(formModel);
|
||||
this.urlInputBox.focus();
|
||||
this.initialized = true;
|
||||
});
|
||||
|
||||
dialog.registerCloseValidator(async () => await this.validate());
|
||||
dialog.okButton.label = loc.connect;
|
||||
dialog.cancelButton.label = loc.cancel;
|
||||
azdata.window.openDialog(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private async validate(): Promise<boolean> {
|
||||
public async validate(): Promise<boolean> {
|
||||
if (!this.urlInputBox.value || !this.usernameInputBox.value || !this.passwordInputBox.value) {
|
||||
return false;
|
||||
}
|
||||
let url = this.urlInputBox.value;
|
||||
// Only support https connections
|
||||
if (url.toLowerCase().startsWith('http://')) {
|
||||
url = url.replace('http', 'https');
|
||||
}
|
||||
// Append https if they didn't type it in
|
||||
if (!url.toLowerCase().startsWith('https://')) {
|
||||
url = `https://${url}`;
|
||||
}
|
||||
// Append default port if one wasn't specified
|
||||
if (!/.*:\d*$/.test(url)) {
|
||||
url = `${url}:30080`;
|
||||
}
|
||||
const controllerInfo: ControllerInfo = {
|
||||
url: this.urlInputBox.value,
|
||||
url: url,
|
||||
name: this.nameInputBox.value ?? '',
|
||||
username: this.usernameInputBox.value,
|
||||
rememberPassword: this.rememberPwCheckBox.checked ?? false,
|
||||
resources: []
|
||||
};
|
||||
const controllerModel = new ControllerModel(this._treeDataProvider, controllerInfo, this.passwordInputBox.value);
|
||||
try {
|
||||
// Validate that we can connect to the controller
|
||||
// Validate that we can connect to the controller, this also populates the controllerRegistration from the connection response.
|
||||
await controllerModel.refresh(false);
|
||||
// default info.name to the name of the controller instance if the user did not specify their own and to a pre-canned default if for some weird reason controller endpoint returned instanceName is also not a valid value
|
||||
controllerModel.info.name = controllerModel.info.name || controllerModel.controllerRegistration?.instanceName || loc.defaultControllerName;
|
||||
} catch (err) {
|
||||
vscode.window.showErrorMessage(loc.connectToControllerFailed(this.urlInputBox.value, err));
|
||||
return false;
|
||||
|
||||
@@ -28,7 +28,7 @@ export class ControllerTreeNode extends TreeNode {
|
||||
private _childrenRefreshPromise = new Deferred();
|
||||
|
||||
constructor(public model: ControllerModel, private _context: vscode.ExtensionContext, private _treeDataProvider: AzureArcTreeDataProvider) {
|
||||
super(model.info.url, vscode.TreeItemCollapsibleState.Collapsed, ResourceType.dataControllers);
|
||||
super(model.label, vscode.TreeItemCollapsibleState.Collapsed, ResourceType.dataControllers);
|
||||
model.onRegistrationsUpdated(registrations => this.refreshChildren(registrations));
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export class ControllerTreeNode extends TreeNode {
|
||||
}
|
||||
// Couldn't get the children and TreeView doesn't have a way to collapse a node
|
||||
// in a way that will refetch its children when expanded again so instead we
|
||||
// display a tempory node that will prompt the user to re-enter credentials
|
||||
// display a temporary node that will prompt the user to re-enter credentials
|
||||
return [new RefreshTreeNode(this)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,42 @@
|
||||
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
|
||||
integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
|
||||
|
||||
"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
|
||||
integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==
|
||||
dependencies:
|
||||
type-detect "4.0.8"
|
||||
|
||||
"@sinonjs/fake-timers@^6.0.0", "@sinonjs/fake-timers@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40"
|
||||
integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@sinonjs/formatio@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089"
|
||||
integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1"
|
||||
"@sinonjs/samsam" "^5.0.2"
|
||||
|
||||
"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.0.3.tgz#86f21bdb3d52480faf0892a480c9906aa5a52938"
|
||||
integrity sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.6.0"
|
||||
lodash.get "^4.4.2"
|
||||
type-detect "^4.0.8"
|
||||
|
||||
"@sinonjs/text-encoding@^0.7.1":
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
|
||||
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
|
||||
|
||||
"@types/caseless@*":
|
||||
version "0.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
|
||||
@@ -212,6 +248,18 @@
|
||||
"@types/tough-cookie" "*"
|
||||
form-data "^2.5.0"
|
||||
|
||||
"@types/sinon@^9.0.4":
|
||||
version "9.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.4.tgz#e934f904606632287a6e7f7ab0ce3f08a0dad4b1"
|
||||
integrity sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw==
|
||||
dependencies:
|
||||
"@types/sinonjs__fake-timers" "*"
|
||||
|
||||
"@types/sinonjs__fake-timers@*":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
|
||||
integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
|
||||
|
||||
"@types/tough-cookie@*":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d"
|
||||
@@ -432,6 +480,11 @@ diff@3.5.0:
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
||||
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
|
||||
|
||||
diff@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
@@ -609,6 +662,11 @@ is-typedarray@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
@@ -716,10 +774,20 @@ jsprim@^1.2.2:
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
just-extend@^4.0.2:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4"
|
||||
integrity sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
|
||||
lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
make-dir@^2.1.0:
|
||||
version "2.1.0"
|
||||
@@ -834,6 +902,17 @@ ms@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nise@^4.0.1:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd"
|
||||
integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
"@sinonjs/fake-timers" "^6.0.0"
|
||||
"@sinonjs/text-encoding" "^0.7.1"
|
||||
just-extend "^4.0.2"
|
||||
path-to-regexp "^1.7.0"
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
@@ -856,6 +935,13 @@ path-parse@^1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
|
||||
path-to-regexp@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
|
||||
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
|
||||
dependencies:
|
||||
isarray "0.0.1"
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
@@ -995,6 +1081,19 @@ should@^13.2.3:
|
||||
should-type-adaptors "^1.0.1"
|
||||
should-util "^1.0.0"
|
||||
|
||||
sinon@^9.0.2:
|
||||
version "9.0.2"
|
||||
resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d"
|
||||
integrity sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.2"
|
||||
"@sinonjs/fake-timers" "^6.0.1"
|
||||
"@sinonjs/formatio" "^5.0.1"
|
||||
"@sinonjs/samsam" "^5.0.3"
|
||||
diff "^4.0.2"
|
||||
nise "^4.0.1"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
source-map@^0.5.0:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
@@ -1078,6 +1177,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
||||
type-detect@4.0.8, type-detect@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
||||
|
||||
typemoq@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8"
|
||||
|
||||
@@ -0,0 +1,522 @@
|
||||
{
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.6.6",
|
||||
"mimetype": "text/x-python",
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"pygments_lexer": "ipython3",
|
||||
"nbconvert_exporter": "python",
|
||||
"file_extension": ".py"
|
||||
}
|
||||
},
|
||||
"nbformat_minor": 2,
|
||||
"nbformat": 4,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"\n",
|
||||
"## Deploy Azure SQL Edge to an Azure VM via IoT hub\n",
|
||||
"This notebook will walk you through the end to end setup of Azure SQL Edge.\n",
|
||||
"1. Create an Azure Edge VM as a virtual IoT device, you can go the \"Default Settings\" cell and adjust the vm_size variable based on your needs. Available sizes and pricing information can be found [here](https://docs.microsoft.com/azure/virtual-machines/linux/sizes).\n",
|
||||
"1. Create an Azure IoT hub, you can go to the \"Default Settings\" cell and adjust value of the following variables based on your needs: iot_hub_sku and iot_hub_units. Available SKUs and pricing information can be found [here](https://azure.microsoft.com/pricing/details/iot-hub/).\n",
|
||||
"1. Add the device to the IoT hub\n",
|
||||
"1. Deploy SQL Edge module to the device with optional dacpac\n",
|
||||
"1. Enable connecting to the SQL Edge instance on the device\n",
|
||||
"\n",
|
||||
"### Dependencies\n",
|
||||
"- Azure CLI. For more information, see [Azure CLI Installation](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest).\n",
|
||||
"\n",
|
||||
"<span style=\"color:red\"><font size=\"3\">Please press the \"Run all\" button to run the notebook</font></span>"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "15b8cfc7-dd7f-4db8-9a3c-2151932fe7b5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Check dependencies"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f78f4ff3-d4c9-4c3e-853f-4add05061eb0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import pandas,sys,os,json,html,getpass,time,ntpath,uuid\n",
|
||||
"pandas_version = pandas.__version__.split('.')\n",
|
||||
"pandas_major = int(pandas_version[0])\n",
|
||||
"pandas_minor = int(pandas_version[1])\n",
|
||||
"pandas_patch = int(pandas_version[2])\n",
|
||||
"if not (pandas_major > 0 or (pandas_major == 0 and pandas_minor > 24) or (pandas_major == 0 and pandas_minor == 24 and pandas_patch >= 2)):\n",
|
||||
" sys.exit('Please upgrade the Notebook dependency before you can proceed, you can do it by running the \"Reinstall Notebook dependencies\" command in command palette (View menu -> Command Palette…).')\n",
|
||||
"\n",
|
||||
"def run_command(command:str, displayCommand:str = \"\", returnObject:bool = False):\n",
|
||||
" print(\"Executing: \" + (displayCommand if displayCommand != \"\" else command))\n",
|
||||
" if returnObject:\n",
|
||||
" output = os.popen(command).read()\n",
|
||||
" print(f'Command successfully executed')\n",
|
||||
" return json.loads(''.join(output))\n",
|
||||
" else:\n",
|
||||
" !{command}\n",
|
||||
" if _exit_code != 0:\n",
|
||||
" sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n')\n",
|
||||
" else:\n",
|
||||
" print(f'Command successfully executed')\n",
|
||||
"\n",
|
||||
"run_command(command='az --version')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "70b9744f-eb59-44e8-9b35-db590ac4651d",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Install Azure IoT extension for Azure CLI"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "a7f15c68-1725-4caa-b4f7-ddc2b4934883"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"run_command('az extension add --name azure-cli-iot-ext')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "55bb2f96-6f7f-4aa0-9daf-d0f7f9d9243c",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Required information"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "b5dc5586-06e8-44d9-8bc3-2861d510efe5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"azure_subscription_id = os.environ[\"AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID\"]\n",
|
||||
"azure_resource_group = os.environ[\"AZDATA_NB_VAR_ASDE_RESOURCEGROUP\"]\n",
|
||||
"azure_location = os.environ[\"AZDATA_NB_VAR_ASDE_AZURE_LOCATION\"]\n",
|
||||
"sa_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n",
|
||||
"vm_admin = os.environ[\"AZDATA_NB_VAR_ASDE_VM_ADMIN\"]\n",
|
||||
"vm_password = os.environ[\"AZDATA_NB_VAR_ASDE_VM_PASSWORD\"]\n",
|
||||
"dacpac_path = os.environ[\"AZDATA_NB_VAR_ASDE_DACPAC_PATH\"]\n",
|
||||
"sql_port = os.environ[\"AZDATA_NB_VAR_ASDE_SQL_PORT\"]\n",
|
||||
"new_rg_flag = os.environ[\"AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP\"]\n",
|
||||
"new_rg_name = os.environ[\"AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP_NAME\"]\n",
|
||||
"\n",
|
||||
"if new_rg_flag == 'true':\n",
|
||||
" azure_resource_group = new_rg_name\n",
|
||||
"print(f'Subscription: {azure_subscription_id}')\n",
|
||||
"print(f'Resource group: {azure_resource_group}')\n",
|
||||
"print(f'Location: {azure_location}')\n",
|
||||
"print(f'VM admin username: {vm_admin}')\n",
|
||||
"print(f'VM admin password: ******')\n",
|
||||
"print(f'SQL Server port: {sql_port}')\n",
|
||||
"print(f'SQL Server sa password: ******')\n",
|
||||
"print(f'Dacpac path: {dacpac_path}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "dde9388b-f623-4d62-bb74-36a05f5d2ea3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Default settings"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "2a5755eb-85a7-4237-8d87-04cdab13cf40"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"suffix = time.strftime(\"%y%m%d%H%M%S\", time.localtime())\n",
|
||||
"network_security_group = f'nsg{suffix}'\n",
|
||||
"public_ip_address_name = f'ip{suffix}'\n",
|
||||
"iot_hub_name = f'hub{suffix}'\n",
|
||||
"iot_hub_sku = 'S1'\n",
|
||||
"iot_hub_units = 4\n",
|
||||
"iot_device_id = f'vm{suffix}'\n",
|
||||
"vm_size = 'Standard_DS3_v2'\n",
|
||||
"vnet_name = f'net{suffix}'\n",
|
||||
"subnet_name = f'subnet{suffix}'\n",
|
||||
"subnet_address_prefix = '10.0.0.0/24'\n",
|
||||
"vnet_address_prefix = '10.0.0.0/16'\n",
|
||||
"azure_storage_account = f'sa{suffix}'\n",
|
||||
"storage_account_container = 'sqldatabasedacpac'\n",
|
||||
"sql_lcid = '1033'\n",
|
||||
"sql_collation = 'SQL_Latin1_General_CP1_CI_AS'"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "19ebeaf4-94c9-4d2b-bd9f-e3c6bf7f2dda",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Login to Azure"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "84f57c09-5772-4f7a-a270-4039b8d5b081"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"run_command('az login')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f9e8ddee-aefa-4951-b767-b318d941d2cd",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Set active Azure subscription"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "59249fa6-f76c-4e5d-bee7-a9ebef6f873e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"if azure_subscription_id != \"\":\n",
|
||||
" run_command(f'az account set --subscription {azure_subscription_id}')\n",
|
||||
"else:\n",
|
||||
" print('Using the default Azure subscription', {azure_subscription_id})\n",
|
||||
"run_command(f'az account show')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "6e085676-2cc5-4af8-819c-fa210244e6c3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create resource group"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "67dacbaa-92f4-4d06-90bb-8974964852aa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"rg_exists = run_command(f'az group exists --name {azure_resource_group}', returnObject=True)\n",
|
||||
"\n",
|
||||
"if rg_exists:\n",
|
||||
" print(f'resource group \\\"{azure_resource_group}\\\" already exists.')\n",
|
||||
"else:\n",
|
||||
" run_command(f'az group create --location {azure_location} --name {azure_resource_group}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f29b439e-cf05-4c35-aa47-1482ccd653bf",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create storage account and storage account container, then upload the dacpac"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "90ec2b26-0c4a-4aa4-b397-f16b09b454ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"if dacpac_path == \"\":\n",
|
||||
" print(f'Dacpac zip file not provided')\n",
|
||||
" blob_sas = ''\n",
|
||||
"else: \n",
|
||||
" dacpac_name = ntpath.basename(dacpac_path)\n",
|
||||
" storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)\n",
|
||||
" storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]\n",
|
||||
" if len(storage_accounts) == 0:\n",
|
||||
" run_command(f'az storage account create -n {azure_storage_account} -g {azure_resource_group} -l {azure_location} --sku Standard_LRS --kind Storage')\n",
|
||||
" else:\n",
|
||||
" print(f'storage account \\\"{azure_storage_account}\\\" already exists.')\n",
|
||||
"\n",
|
||||
" storage_account_key = run_command(f'az storage account keys list --account-name {azure_storage_account} --resource-group {azure_resource_group}', returnObject=True)[0]['value']\n",
|
||||
" container_exists = run_command(f'az storage container exists --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key --output json', returnObject=True)['exists']\n",
|
||||
" if container_exists:\n",
|
||||
" print(f'storage account container \\\"{storage_account_container}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')\n",
|
||||
"\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" if blob_exists:\n",
|
||||
" print(f'blob \\\"{dacpac_name}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {dacpac_name} --file \\\"{dacpac_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" now = time.localtime()\n",
|
||||
" expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'\n",
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "7ab2b3ec-0832-40b3-98c0-4aa87320e7ce",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create network security group"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "b308771b-138a-40ce-a9d3-1d15094d537b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"nsg_list = run_command(f'az network nsg list --resource-group {azure_resource_group}', returnObject=True)\n",
|
||||
"nsg_list = [nsg for nsg in nsg_list if nsg['name'] == network_security_group]\n",
|
||||
"if len(nsg_list) == 0:\n",
|
||||
" run_command(f'az network nsg create --name {network_security_group} --resource-group {azure_resource_group} --location {azure_location}')\n",
|
||||
" run_command(f'az network nsg rule create --name \\\"SQL\\\" --nsg-name {network_security_group} --priority 100 --resource-group {azure_resource_group} --access Allow --description \\\"Allow SQL\\\" --destination-address-prefixes \\\"*\\\" --destination-port-ranges {sql_port} --direction Inbound --source-address-prefixes Internet --protocol Tcp')\n",
|
||||
"else:\n",
|
||||
" print(f'Network security group \\\"{network_security_group}\\\" already exists.')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "99cbb95c-b109-4b2e-909b-ff71a62754fb",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create an Edge enabled VM as an Edge device"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "41b10249-cd40-4053-b1b0-b02f562789f7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"vm_list = run_command(f'az vm list --resource-group {azure_resource_group}', returnObject=True)\n",
|
||||
"vm_list = [vm for vm in vm_list if vm['name'] == iot_device_id]\n",
|
||||
"if len(vm_list) == 0:\n",
|
||||
" vm_image = run_command(f'az vm image list --all --location {azure_location} --offer iot_edge_vm_ubuntu --publisher microsoft_iot_edge --sku ubuntu_1604_edgeruntimeonly', returnObject=True)\n",
|
||||
" image_urn = vm_image[0]['urn']\n",
|
||||
" run_command(f'az vm image terms accept --urn {image_urn}')\n",
|
||||
" vm_password_placeholder = '<admin_password>'\n",
|
||||
" create_vm_command_template = f'az vm create --name {iot_device_id} --resource-group {azure_resource_group} --admin-username {vm_admin} --admin-password {vm_password_placeholder} --authentication-type password --image {image_urn} --location {azure_location} --nsg {network_security_group} --public-ip-address \\\"{public_ip_address_name}\\\" --public-ip-address-allocation static --public-ip-sku Standard --size {vm_size} --subnet {subnet_name} --subnet-address-prefix \\\"{subnet_address_prefix}\\\" --vnet-name {vnet_name} --vnet-address-prefix \\\"{vnet_address_prefix}\\\"'\n",
|
||||
" run_command(create_vm_command_template.replace(vm_password_placeholder, vm_password), displayCommand=create_vm_command_template.replace(vm_password_placeholder, '******'))\n",
|
||||
"else:\n",
|
||||
" print(f'VM \\\"{iot_device_id}\\\" already exists, skipping the vm creation.')\n",
|
||||
"ip_address = run_command(f'az vm show -d -g {azure_resource_group} -n {iot_device_id} --query publicIps', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "157fc38f-cf2a-40c6-9c9e-88f45cc5c62f",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create IoT hub"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "e37a04c3-515d-4cb7-99b2-f8bc6167510e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"hub_list = run_command(f'az iot hub list --resource-group {azure_resource_group}', returnObject=True)\n",
|
||||
"hub_list = [hub for hub in hub_list if hub['name'] == iot_hub_name]\n",
|
||||
"if len(hub_list) == 0:\n",
|
||||
" run_command(f'az iot hub create --name {iot_hub_name} --resource-group {azure_resource_group} --location {azure_location} --sku {iot_hub_sku} --unit {iot_hub_units}')\n",
|
||||
"else:\n",
|
||||
" print(f'IoT hub \\\"{iot_hub_name}\\\" already exists')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f9f5e4ec-82a5-45df-a408-ddb0fb21847c",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Add the Edge device to the IoT hub"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "fbc5f4ac-dfe0-4543-ace1-49b796251910"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"device_list = run_command(f'az iot hub device-identity list --edge-enabled true --hub-name {iot_hub_name} --resource-group {azure_resource_group}', returnObject=True)\n",
|
||||
"device_list = [device for device in device_list if device['deviceId'] == iot_device_id]\n",
|
||||
"if len(device_list) == 0:\n",
|
||||
" run_command(f'az iot hub device-identity create --device-id {iot_device_id} --hub-name {iot_hub_name} --resource-group {azure_resource_group} --edge-enabled true')\n",
|
||||
"else:\n",
|
||||
" print(f'Edge device \\\"{iot_device_id}\\\" already exists.')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "c183c3e3-8699-4f29-993b-07bf848336e3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Configure Edge on the device"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "069db017-9169-499a-839b-9cd73ea7d01e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"connection_string = run_command(f'az iot hub device-identity show-connection-string --device-id {iot_device_id} --hub-name {iot_hub_name} --resource-group {azure_resource_group}', returnObject=True)\n",
|
||||
"connection_string = connection_string['connectionString']\n",
|
||||
"script = f'/etc/iotedge/configedge.sh \\'{connection_string}\\''\n",
|
||||
"run_command(f'az vm run-command invoke -g {azure_resource_group} -n {iot_device_id} --command-id RunShellScript --script \\\"{script}\\\"')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "9ec1e31a-79aa-49f4-a0e5-16f8d7c2dd21",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Deploy Azure SQL Edge to the device"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "ec46957f-0795-4c75-804d-f8a7ecb26382"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge-developer\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"MSSQL_PID=Developer\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"SqlPackage\\\":\\\"<Optional_DACPAC_ZIP_SAS_URL>\\\",\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_ZIP_SAS_URL>\\\"}}}}'\n",
|
||||
"manifest = manifest.replace('<Optional_DACPAC_ZIP_SAS_URL>', blob_sas).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"file_name = f'{uuid.uuid4().hex}.json'\n",
|
||||
"manifest_file = open(file_name, 'w')\n",
|
||||
"manifest_file.write(manifest)\n",
|
||||
"manifest_file.close()\n",
|
||||
"run_command(f'az iot edge set-modules --device-id \\\"{iot_device_id}\\\" --hub-name \\\"{iot_hub_name}\\\" --content \\\"{file_name}\\\" --resource-group {azure_resource_group}')\n",
|
||||
"os.remove(file_name)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "81a86ff6-5a83-48be-8be7-654d152eea89",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### **Connect to Azure SQL Edge instance in Azure Data Studio**\n",
|
||||
"Click the link below to connect to the Azure SQL Edge instance, it might take a couple minutes for the service to start."
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "3bdfa537-a749-45c4-b219-57d296c22739"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from IPython.display import *\n",
|
||||
"connectionParameter = '{\"serverName\":\"' + f'{ip_address},{sql_port}' + '\",\"providerName\":\"MSSQL\",\"authenticationType\":\"SqlLogin\",\"userName\": \"sa\",\"password\":' + json.dumps(sa_password) + '}'\n",
|
||||
"display(HTML('<br/><a href=\"command:azdata.connect?' + html.escape(connectionParameter)+'\"><font size=\"3\">Click here to connect to the Azure SQL Edge instance</font></a><br/>'))\n",
|
||||
"display(HTML('<br/><span style=\"color:red\"><font size=\"2\">NOTE: The Azure SQL Edge instance password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "8bc29cce-96a7-4a78-89af-5c73a6431c24",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"\n",
|
||||
"## Run Azure SQL Edge image locally with Docker\n",
|
||||
"## Deploy Azure SQL Edge container instance locally with Docker\n",
|
||||
"This notebook will use Docker to pull and run the Azure SQL Edge image and connect to it in Azure Data Studio\n",
|
||||
"\n",
|
||||
"### Dependencies\n",
|
||||
@@ -233,8 +233,8 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Connect to SQL Server in Azure Data Studio\n",
|
||||
"It might take a couple minutes for SQL Server to launch"
|
||||
"### Connect to Azure SQL Edge instance in Azure Data Studio\n",
|
||||
"It might take a couple minutes for the service to launch"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "c84bc075-f8b2-48a3-bfc7-f07a5b8be7a0"
|
||||
@@ -245,8 +245,8 @@
|
||||
"source": [
|
||||
"from IPython.display import *\n",
|
||||
"connectionParameter = '{\"serverName\":\"localhost,' + sql_port + '\",\"providerName\":\"MSSQL\",\"authenticationType\":\"SqlLogin\",\"userName\":\"sa\",\"password\":' + json.dumps(sql_password) + '}'\n",
|
||||
"display(HTML('<br/><a href=\"command:azdata.connect?' + html.escape(connectionParameter)+'\"><font size=\"3\">Click here to connect to SQL Server</font></a><br/>'))\n",
|
||||
"display(HTML('<br/><span style=\"color:red\"><font size=\"2\">NOTE: The SQL Server password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))"
|
||||
"display(HTML('<br/><a href=\"command:azdata.connect?' + html.escape(connectionParameter)+'\"><font size=\"3\">Click here to connect to the Azure SQL Edge instance</font></a><br/>'))\n",
|
||||
"display(HTML('<br/><span style=\"color:red\"><font size=\"2\">NOTE: The Azure SQL Edge instance password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "187a0067-a04c-4afb-a684-3103bb4522ae",
|
||||
@@ -285,4 +285,4 @@
|
||||
"execution_count": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
{
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.6.6",
|
||||
"mimetype": "text/x-python",
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"pygments_lexer": "ipython3",
|
||||
"nbconvert_exporter": "python",
|
||||
"file_extension": ".py"
|
||||
}
|
||||
},
|
||||
"nbformat_minor": 2,
|
||||
"nbformat": 4,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"\n",
|
||||
"## Deploy Azure SQL Edge to multiple devices via IoT hub\n",
|
||||
"This notebook will walk you through process of deploying Azure SQL Edge to multiple devices of an IoT hub.\n",
|
||||
"\n",
|
||||
"### Dependencies\n",
|
||||
"- Azure CLI. For more information, see [Azure CLI Installation](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest).\n",
|
||||
"\n",
|
||||
"<span style=\"color:red\"><font size=\"3\">Please press the \"Run all\" button to run the notebook</font></span>"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "15b8cfc7-dd7f-4db8-9a3c-2151932fe7b5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Check dependencies"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f78f4ff3-d4c9-4c3e-853f-4add05061eb0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import pandas,sys,os,json,html,getpass,time,ntpath,uuid\n",
|
||||
"pandas_version = pandas.__version__.split('.')\n",
|
||||
"pandas_major = int(pandas_version[0])\n",
|
||||
"pandas_minor = int(pandas_version[1])\n",
|
||||
"pandas_patch = int(pandas_version[2])\n",
|
||||
"if not (pandas_major > 0 or (pandas_major == 0 and pandas_minor > 24) or (pandas_major == 0 and pandas_minor == 24 and pandas_patch >= 2)):\n",
|
||||
" sys.exit('Please upgrade the Notebook dependency before you can proceed, you can do it by running the \"Reinstall Notebook dependencies\" command in command palette (View menu -> Command Palette…).')\n",
|
||||
"\n",
|
||||
"def run_command(command:str, displayCommand:str = \"\", returnObject:bool = False):\n",
|
||||
" print(\"Executing: \" + (displayCommand if displayCommand != \"\" else command))\n",
|
||||
" if returnObject:\n",
|
||||
" output = os.popen(command).read()\n",
|
||||
" print(f'Command successfully executed')\n",
|
||||
" return json.loads(''.join(output))\n",
|
||||
" else:\n",
|
||||
" !{command}\n",
|
||||
" if _exit_code != 0:\n",
|
||||
" sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n')\n",
|
||||
" else:\n",
|
||||
" print(f'Command successfully executed')\n",
|
||||
"\n",
|
||||
"run_command(command='az --version')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "70b9744f-eb59-44e8-9b35-db590ac4651d",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Install Azure IoT extension for Azure CLI"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "a7f15c68-1725-4caa-b4f7-ddc2b4934883"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"run_command('az extension add --name azure-cli-iot-ext')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "55bb2f96-6f7f-4aa0-9daf-d0f7f9d9243c",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Required information"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "b5dc5586-06e8-44d9-8bc3-2861d510efe5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"azure_subscription_id = os.environ[\"AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID\"]\n",
|
||||
"azure_resource_group = os.environ[\"AZDATA_NB_VAR_ASDE_RESOURCEGROUP\"]\n",
|
||||
"sa_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n",
|
||||
"dacpac_path = os.environ[\"AZDATA_NB_VAR_ASDE_DACPAC_PATH\"]\n",
|
||||
"sql_port = os.environ[\"AZDATA_NB_VAR_ASDE_SQL_PORT\"]\n",
|
||||
"iot_hub_name = os.environ[\"AZDATA_NB_VAR_ASDE_HUBNAME\"]\n",
|
||||
"target_condition = os.environ[\"AZDATA_NB_VAR_ASDE_TARGET_CONDITION\"]\n",
|
||||
"print(f'Subscription: {azure_subscription_id}')\n",
|
||||
"print(f'Resource group: {azure_resource_group}')\n",
|
||||
"print(f'IoT hub name: {iot_hub_name}')\n",
|
||||
"print(f'Target condition: {target_condition}')\n",
|
||||
"print(f'Azure SQL Edge instance port: {sql_port}')\n",
|
||||
"print(f'Azure SQL Edge instance sa password: ******')\n",
|
||||
"print(f'Dacpac path: {dacpac_path}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "dde9388b-f623-4d62-bb74-36a05f5d2ea3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Default settings"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "2a5755eb-85a7-4237-8d87-04cdab13cf40"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"suffix = time.strftime(\"%y%m%d%H%M%S\", time.localtime())\n",
|
||||
"azure_storage_account = f'sa{suffix}'\n",
|
||||
"deployment_id = f'asde{suffix}'\n",
|
||||
"storage_account_container = 'sqldatabasedacpac'\n",
|
||||
"sql_lcid = '1033'\n",
|
||||
"sql_collation = 'SQL_Latin1_General_CP1_CI_AS'\n",
|
||||
"deployment_priority = 10"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "19ebeaf4-94c9-4d2b-bd9f-e3c6bf7f2dda",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Login to Azure"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "84f57c09-5772-4f7a-a270-4039b8d5b081"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"run_command('az login')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f9e8ddee-aefa-4951-b767-b318d941d2cd",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Set active Azure subscription"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "59249fa6-f76c-4e5d-bee7-a9ebef6f873e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"if azure_subscription_id != \"\":\n",
|
||||
" run_command(f'az account set --subscription {azure_subscription_id}')\n",
|
||||
"else:\n",
|
||||
" print('Using the default Azure subscription', {azure_subscription_id})\n",
|
||||
"run_command(f'az account show')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "6e085676-2cc5-4af8-819c-fa210244e6c3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Make sure the IoT hub exists"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "b207680d-a0df-49b5-9e9e-5fd8c3d492d3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"hub_list = run_command(f'az iot hub list --resource-group {azure_resource_group}', returnObject=True)\r\n",
|
||||
"hub_list = [hub for hub in hub_list if hub['name'] == iot_hub_name]\r\n",
|
||||
"if len(hub_list) == 0:\r\n",
|
||||
" sys.exit(f'IoT hub \\\"{iot_hub_name}\\\" does not exist.')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "38798c56-b2a0-4af8-b39e-5e26f3c79aeb",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create storage account and storage account container, then upload the dacpac"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "90ec2b26-0c4a-4aa4-b397-f16b09b454ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"if dacpac_path == \"\":\n",
|
||||
" print(f'Dacpac zip file not provided')\n",
|
||||
" blob_sas = ''\n",
|
||||
"else:\n",
|
||||
" dacpac_name = ntpath.basename(dacpac_path)\n",
|
||||
" storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)\n",
|
||||
" storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]\n",
|
||||
" if len(storage_accounts) == 0:\n",
|
||||
" run_command(f'az storage account create -n {azure_storage_account} -g {azure_resource_group} --sku Standard_LRS --kind Storage')\n",
|
||||
" else:\n",
|
||||
" print(f'storage account \\\"{azure_storage_account}\\\" already exists.')\n",
|
||||
"\n",
|
||||
" storage_account_key = run_command(f'az storage account keys list --account-name {azure_storage_account} --resource-group {azure_resource_group}', returnObject=True)[0]['value']\n",
|
||||
" container_exists = run_command(f'az storage container exists --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key --output json', returnObject=True)['exists']\n",
|
||||
" if container_exists:\n",
|
||||
" print(f'storage account container \\\"{storage_account_container}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')\n",
|
||||
"\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" if blob_exists:\n",
|
||||
" print(f'blob \\\"{dacpac_name}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {dacpac_name} --file \\\"{dacpac_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" now = time.localtime()\n",
|
||||
" expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'\n",
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "7ab2b3ec-0832-40b3-98c0-4aa87320e7ce",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Deploy Azure SQL Edge to the device"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "ec46957f-0795-4c75-804d-f8a7ecb26382"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge-developer\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"MSSQL_PID=Developer\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"SqlPackage\\\":\\\"<Optional_DACPAC_ZIP_SAS_URL>\\\",\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_ZIP_SAS_URL>\\\"}}}}'\n",
|
||||
"manifest = manifest.replace('<Optional_DACPAC_ZIP_SAS_URL>', blob_sas).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"file_name = f'{uuid.uuid4().hex}.json'\n",
|
||||
"manifest_file = open(file_name, 'w')\n",
|
||||
"manifest_file.write(manifest)\n",
|
||||
"manifest_file.close()\n",
|
||||
"run_command(f'az iot edge deployment create --target-condition \\\"{target_condition}\\\" --hub-name \\\"{iot_hub_name}\\\" --content \\\"{file_name}\\\" --deployment-id \\\"{deployment_id}\\\" --priority {deployment_priority}')\n",
|
||||
"os.remove(file_name)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "81a86ff6-5a83-48be-8be7-654d152eea89",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"\n",
|
||||
"## Run Azure SQL DB Edge image on a remote machine with Docker\n",
|
||||
"## Deploy Azure SQL Edge container instance on a remote machine with Docker\n",
|
||||
"This notebook will use SSH to connect to the remote machine, use Docker to pull and run the Azure SQL Edge image and connect to it in Azure Data Studio\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -300,8 +300,8 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Connect to SQL Server in Azure Data Studio\n",
|
||||
"It might take a couple minutes for SQL Server to launch"
|
||||
"### Connect to Azure SQL Edge instance in Azure Data Studio\n",
|
||||
"It might take a couple minutes for the service to launch"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "c84bc075-f8b2-48a3-bfc7-f07a5b8be7a0"
|
||||
@@ -312,8 +312,8 @@
|
||||
"source": [
|
||||
"from IPython.display import *\n",
|
||||
"connectionParameter = '{\"serverName\":\"' + ssh_target + ',' + sql_port + '\",\"providerName\":\"MSSQL\",\"authenticationType\":\"SqlLogin\",\"userName\":\"sa\",\"password\":' + json.dumps(sql_password) + '}'\n",
|
||||
"display(HTML('<br/><a href=\"command:azdata.connect?' + html.escape(connectionParameter)+'\"><font size=\"3\">Click here to connect to SQL Server</font></a><br/>'))\n",
|
||||
"display(HTML('<br/><span style=\"color:red\"><font size=\"2\">NOTE: The SQL Server password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))"
|
||||
"display(HTML('<br/><a href=\"command:azdata.connect?' + html.escape(connectionParameter)+'\"><font size=\"3\">Click here to connect to the Azure SQL Edge instance</font></a><br/>'))\n",
|
||||
"display(HTML('<br/><span style=\"color:red\"><font size=\"2\">NOTE: The Azure SQL Edge instance password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "187a0067-a04c-4afb-a684-3103bb4522ae",
|
||||
@@ -358,10 +358,12 @@
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "9f2c9d3a-b996-4977-81f5-05a79a2e0e12",
|
||||
"tags": []
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
{
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.6.6",
|
||||
"mimetype": "text/x-python",
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"pygments_lexer": "ipython3",
|
||||
"nbconvert_exporter": "python",
|
||||
"file_extension": ".py"
|
||||
}
|
||||
},
|
||||
"nbformat_minor": 2,
|
||||
"nbformat": 4,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"\n",
|
||||
"## Deploy Azure SQL Edge to an existing device via IoT hub\n",
|
||||
"This notebook will walk you through process of deploying Azure SQL Edge to an existing device of an IoT hub:\n",
|
||||
"1. Deploy Azure SQL Edge module to the device with optional dacpac\n",
|
||||
"1. If a dacpac is selected, a storage account will be created to host the dacpac file\n",
|
||||
"1. Enable connecting to the Azure SQL Edge instance on the device\n",
|
||||
"\n",
|
||||
"### Dependencies\n",
|
||||
"- Azure CLI. For more information, see [Azure CLI Installation](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest).\n",
|
||||
"\n",
|
||||
"<span style=\"color:red\"><font size=\"3\">Please press the \"Run all\" button to run the notebook</font></span>"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "15b8cfc7-dd7f-4db8-9a3c-2151932fe7b5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Check dependencies"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f78f4ff3-d4c9-4c3e-853f-4add05061eb0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import pandas,sys,os,json,html,getpass,time,ntpath,uuid\n",
|
||||
"pandas_version = pandas.__version__.split('.')\n",
|
||||
"pandas_major = int(pandas_version[0])\n",
|
||||
"pandas_minor = int(pandas_version[1])\n",
|
||||
"pandas_patch = int(pandas_version[2])\n",
|
||||
"if not (pandas_major > 0 or (pandas_major == 0 and pandas_minor > 24) or (pandas_major == 0 and pandas_minor == 24 and pandas_patch >= 2)):\n",
|
||||
" sys.exit('Please upgrade the Notebook dependency before you can proceed, you can do it by running the \"Reinstall Notebook dependencies\" command in command palette (View menu -> Command Palette…).')\n",
|
||||
"\n",
|
||||
"def run_command(command:str, displayCommand:str = \"\", returnObject:bool = False):\n",
|
||||
" print(\"Executing: \" + (displayCommand if displayCommand != \"\" else command))\n",
|
||||
" if returnObject:\n",
|
||||
" output = os.popen(command).read()\n",
|
||||
" print(f'Command successfully executed')\n",
|
||||
" return json.loads(''.join(output))\n",
|
||||
" else:\n",
|
||||
" !{command}\n",
|
||||
" if _exit_code != 0:\n",
|
||||
" sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n')\n",
|
||||
" else:\n",
|
||||
" print(f'Command successfully executed')\n",
|
||||
"\n",
|
||||
"run_command(command='az --version')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "70b9744f-eb59-44e8-9b35-db590ac4651d",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Install Azure IoT extension for Azure CLI"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "a7f15c68-1725-4caa-b4f7-ddc2b4934883"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"run_command('az extension add --name azure-cli-iot-ext')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "55bb2f96-6f7f-4aa0-9daf-d0f7f9d9243c",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Required information"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "b5dc5586-06e8-44d9-8bc3-2861d510efe5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"azure_subscription_id = os.environ[\"AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID\"]\n",
|
||||
"azure_resource_group = os.environ[\"AZDATA_NB_VAR_ASDE_RESOURCEGROUP\"]\n",
|
||||
"sa_password = os.environ[\"AZDATA_NB_VAR_SA_PASSWORD\"]\n",
|
||||
"dacpac_path = os.environ[\"AZDATA_NB_VAR_ASDE_DACPAC_PATH\"]\n",
|
||||
"sql_port = os.environ[\"AZDATA_NB_VAR_ASDE_SQL_PORT\"]\n",
|
||||
"iot_hub_name = os.environ[\"AZDATA_NB_VAR_ASDE_HUBNAME\"]\n",
|
||||
"iot_device_id = os.environ[\"AZDATA_NB_VAR_ASDE_DEVICE_ID\"]\n",
|
||||
"ip_address = os.environ[\"AZDATA_NB_VAR_ASDE_DEVICE_IP_ADDRESS\"]\n",
|
||||
"print(f'Subscription: {azure_subscription_id}')\n",
|
||||
"print(f'Resource group: {azure_resource_group}')\n",
|
||||
"print(f'IoT hub name: {iot_hub_name}')\n",
|
||||
"print(f'Device ID: {iot_device_id}')\n",
|
||||
"print(f'Device IP address: {ip_address}')\n",
|
||||
"print(f'Azure SQL Edge instance port: {sql_port}')\n",
|
||||
"print(f'Azure SQL Edge instance sa password: ******')\n",
|
||||
"print(f'Dacpac path: {dacpac_path}')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "dde9388b-f623-4d62-bb74-36a05f5d2ea3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Default settings"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "2a5755eb-85a7-4237-8d87-04cdab13cf40"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"suffix = time.strftime(\"%y%m%d%H%M%S\", time.localtime())\n",
|
||||
"azure_storage_account = f'sa{suffix}'\n",
|
||||
"storage_account_container = 'sqldatabasedacpac'\n",
|
||||
"sql_lcid = '1033'\n",
|
||||
"sql_collation = 'SQL_Latin1_General_CP1_CI_AS'"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "19ebeaf4-94c9-4d2b-bd9f-e3c6bf7f2dda",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Login to Azure"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "84f57c09-5772-4f7a-a270-4039b8d5b081"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"run_command('az login')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "f9e8ddee-aefa-4951-b767-b318d941d2cd",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Set active Azure subscription"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "59249fa6-f76c-4e5d-bee7-a9ebef6f873e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"if azure_subscription_id != \"\":\n",
|
||||
" run_command(f'az account set --subscription {azure_subscription_id}')\n",
|
||||
"else:\n",
|
||||
" print('Using the default Azure subscription', {azure_subscription_id})\n",
|
||||
"run_command(f'az account show')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "6e085676-2cc5-4af8-819c-fa210244e6c3",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Make sure the IoT hub and device both exist"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "b207680d-a0df-49b5-9e9e-5fd8c3d492d3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"hub_list = run_command(f'az iot hub list --resource-group {azure_resource_group}', returnObject=True)\r\n",
|
||||
"hub_list = [hub for hub in hub_list if hub['name'] == iot_hub_name]\r\n",
|
||||
"if len(hub_list) == 0:\r\n",
|
||||
" sys.exit(f'IoT hub \\\"{iot_hub_name}\\\" does not exist.')\r\n",
|
||||
"\r\n",
|
||||
"device_list = run_command(f'az iot hub device-identity list --edge-enabled true --hub-name {iot_hub_name} --resource-group {azure_resource_group}', returnObject=True)\r\n",
|
||||
"device_list = [device for device in device_list if device['deviceId'] == iot_device_id]\r\n",
|
||||
"if len(device_list) == 0:\r\n",
|
||||
" sys.exit(f'Edge device \\\"{iot_device_id}\\\" does not exist.')"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "38798c56-b2a0-4af8-b39e-5e26f3c79aeb",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Create storage account and storage account container, then upload the dacpac"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "90ec2b26-0c4a-4aa4-b397-f16b09b454ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"if dacpac_path == \"\":\n",
|
||||
" print(f'Dacpac zip file not provided')\n",
|
||||
" blob_sas = ''\n",
|
||||
"else:\n",
|
||||
" dacpac_name = ntpath.basename(dacpac_path)\n",
|
||||
" storage_accounts = run_command(f'az storage account list --resource-group {azure_resource_group} --subscription {azure_subscription_id}', returnObject=True)\n",
|
||||
" storage_accounts = [storage_account for storage_account in storage_accounts if storage_account['name'] == azure_storage_account]\n",
|
||||
" if len(storage_accounts) == 0:\n",
|
||||
" run_command(f'az storage account create -n {azure_storage_account} -g {azure_resource_group} --sku Standard_LRS --kind Storage')\n",
|
||||
" else:\n",
|
||||
" print(f'storage account \\\"{azure_storage_account}\\\" already exists.')\n",
|
||||
"\n",
|
||||
" storage_account_key = run_command(f'az storage account keys list --account-name {azure_storage_account} --resource-group {azure_resource_group}', returnObject=True)[0]['value']\n",
|
||||
" container_exists = run_command(f'az storage container exists --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key --output json', returnObject=True)['exists']\n",
|
||||
" if container_exists:\n",
|
||||
" print(f'storage account container \\\"{storage_account_container}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage container create --name {storage_account_container} --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key')\n",
|
||||
"\n",
|
||||
" blob_exists = run_command(f'az storage blob exists --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-key {storage_account_key} --account-name {azure_storage_account} --auth-mode key', returnObject=True)['exists']\n",
|
||||
" if blob_exists:\n",
|
||||
" print(f'blob \\\"{dacpac_name}\\\" already exists.')\n",
|
||||
" else:\n",
|
||||
" run_command(f'az storage blob upload --account-name {azure_storage_account} --container-name {storage_account_container} --name {dacpac_name} --file \\\"{dacpac_path}\\\" --account-key {storage_account_key} --auth-mode key')\n",
|
||||
" now = time.localtime()\n",
|
||||
" expiry = f'{(now.tm_year + 1)}-{now.tm_mon}-{now.tm_mday}'\n",
|
||||
" blob_sas = run_command(f'az storage blob generate-sas --container-name {storage_account_container} --name \\\"{dacpac_name}\\\" --account-name {azure_storage_account} --account-key {storage_account_key} --auth-mode key --full-uri --https-only --permissions r --expiry {expiry}', returnObject=True)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "7ab2b3ec-0832-40b3-98c0-4aa87320e7ce",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Deploy Azure SQL Edge to the device"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "ec46957f-0795-4c75-804d-f8a7ecb26382"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"manifest = '{\\\"modulesContent\\\":{\\\"$edgeAgent\\\":{\\\"properties.desired\\\":{\\\"modules\\\":{\\\"AzureSQLEdge\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azure-sql-edge-developer\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"CapAdd\\\\\\\":[\\\\\\\"SYS_PTRACE\\\\\\\"],\\\\\\\"Binds\\\\\\\":[\\\\\\\"sqlvolume:/sqlvolume\\\\\\\"],\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"1433/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"<SQL_Port>\\\\\\\"}]},\\\\\\\"Mounts\\\\\\\":[{\\\\\\\"Type\\\\\\\":\\\\\\\"volume\\\\\\\",\\\\\\\"Source\\\\\\\":\\\\\\\"sqlvolume\\\\\\\",\\\\\\\"Target\\\\\\\":\\\\\\\"/var/opt/mssql\\\\\\\"}]},\\\\\\\"User\\\\\\\":\\\\\\\"0:0\\\\\\\",\\\\\\\"Env\\\\\\\":[\\\\\\\"MSSQL_AGENT_ENABLED=TRUE\\\\\\\",\\\\\\\"ClientTransportType=AMQP_TCP_Only\\\\\\\",\\\\\\\"MSSQL_PID=Developer\\\\\\\"]}\\\"},\\\"type\\\":\\\"docker\\\",\\\"version\\\":\\\"1.0\\\",\\\"env\\\":{\\\"ACCEPT_EULA\\\":{\\\"value\\\":\\\"Y\\\"},\\\"SA_PASSWORD\\\":{\\\"value\\\":\\\"<Default_SQL_SA_Password>\\\"},\\\"MSSQL_LCID\\\":{\\\"value\\\":\\\"<SQL_LCID>\\\"},\\\"MSSQL_COLLATION\\\":{\\\"value\\\":\\\"<SQL_Collation>\\\"}},\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}},\\\"runtime\\\":{\\\"settings\\\":{\\\"minDockerVersion\\\":\\\"v1.25\\\"},\\\"type\\\":\\\"docker\\\"},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"systemModules\\\":{\\\"edgeAgent\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-agent:1.0\\\",\\\"createOptions\\\":\\\"\\\"},\\\"type\\\":\\\"docker\\\"},\\\"edgeHub\\\":{\\\"settings\\\":{\\\"image\\\":\\\"mcr.microsoft.com/azureiotedge-hub:1.0\\\",\\\"createOptions\\\":\\\"{\\\\\\\"HostConfig\\\\\\\":{\\\\\\\"PortBindings\\\\\\\":{\\\\\\\"443/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"443\\\\\\\"}],\\\\\\\"5671/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"5671\\\\\\\"}],\\\\\\\"8883/tcp\\\\\\\":[{\\\\\\\"HostPort\\\\\\\":\\\\\\\"8883\\\\\\\"}]}}}\\\"},\\\"type\\\":\\\"docker\\\",\\\"status\\\":\\\"running\\\",\\\"restartPolicy\\\":\\\"always\\\"}}}},\\\"$edgeHub\\\":{\\\"properties.desired\\\":{\\\"routes\\\":{},\\\"schemaVersion\\\":\\\"1.0\\\",\\\"storeAndForwardConfiguration\\\":{\\\"timeToLiveSecs\\\":7200}}},\\\"AzureSQLEdge\\\":{\\\"properties.desired\\\":{\\\"SqlPackage\\\":\\\"<Optional_DACPAC_ZIP_SAS_URL>\\\",\\\"ASAJobInfo\\\":\\\"<Optional_ASA_Job_ZIP_SAS_URL>\\\"}}}}'\n",
|
||||
"manifest = manifest.replace('<Optional_DACPAC_ZIP_SAS_URL>', blob_sas).replace('<Default_SQL_SA_Password>',sa_password).replace('<SQL_LCID>',sql_lcid).replace('<SQL_Port>',sql_port).replace('<SQL_Collation>',sql_collation)\n",
|
||||
"file_name = f'{uuid.uuid4().hex}.json'\n",
|
||||
"manifest_file = open(file_name, 'w')\n",
|
||||
"manifest_file.write(manifest)\n",
|
||||
"manifest_file.close()\n",
|
||||
"run_command(f'az iot edge set-modules --device-id \\\"{iot_device_id}\\\" --hub-name \\\"{iot_hub_name}\\\" --content \\\"{file_name}\\\"')\n",
|
||||
"os.remove(file_name)"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "81a86ff6-5a83-48be-8be7-654d152eea89",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### **Connect to Azure SQL Edge instance in Azure Data Studio**\n",
|
||||
"Click the link below to connect to the Azure SQL Edge instance, it might take a couple minutes for the service to start."
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "3bdfa537-a749-45c4-b219-57d296c22739"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from IPython.display import *\n",
|
||||
"if ip_address == \"\":\n",
|
||||
" print('Connect to Azure SQL Edge instance feature not available because device ip address is not provided')\n",
|
||||
"else:\n",
|
||||
" connectionParameter = '{\"serverName\":\"' + f'{ip_address},{sql_port}' + '\",\"providerName\":\"MSSQL\",\"authenticationType\":\"SqlLogin\",\"userName\": \"sa\",\"password\":' + json.dumps(sa_password) + '}'\n",
|
||||
" display(HTML('<br/><a href=\"command:azdata.connect?' + html.escape(connectionParameter)+'\"><font size=\"3\">Click here to connect to the Azure SQL Edge instance</font></a><br/>'))\n",
|
||||
" display(HTML('<br/><span style=\"color:red\"><font size=\"2\">NOTE: The Azure SQL Edge instance password is included in this link, you may want to clear the results of this code cell before saving the notebook.</font></span>'))"
|
||||
],
|
||||
"metadata": {
|
||||
"azdata_cell_guid": "8bc29cce-96a7-4a78-89af-5c73a6431c24",
|
||||
"tags": [
|
||||
"hide_input"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -41,6 +41,18 @@
|
||||
{
|
||||
"name": "remote",
|
||||
"displayName": "%sql-edge-remote-display-name%"
|
||||
},
|
||||
{
|
||||
"name": "azure-create-new",
|
||||
"displayName": "%sql-edge-azure-display-name%"
|
||||
},
|
||||
{
|
||||
"name": "azure-single-device",
|
||||
"displayName": "%sql-edge-azure-single-device-display-name%"
|
||||
},
|
||||
{
|
||||
"name": "azure-multi-device",
|
||||
"displayName": "%sql-edge-azure-multi-device-display-name%"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -48,7 +60,7 @@
|
||||
"providers": [
|
||||
{
|
||||
"dialog": {
|
||||
"notebook": "%sql-edge-local-notebook%",
|
||||
"notebook": "./notebooks/edge/deploy-sql-edge-local.ipynb",
|
||||
"title": "%sql-edge-local-title%",
|
||||
"name": "sql-edge-local-dialog",
|
||||
"tabs": [
|
||||
@@ -141,7 +153,7 @@
|
||||
},
|
||||
{
|
||||
"dialog": {
|
||||
"notebook": "%sql-edge-remote-notebook%",
|
||||
"notebook": "./notebooks/edge/deploy-sql-edge-remote.ipynb",
|
||||
"title": "%sql-edge-remote-title%",
|
||||
"name": "sql-edge-remote-dialog",
|
||||
"tabs": [
|
||||
@@ -255,6 +267,304 @@
|
||||
},
|
||||
"requiredTools": [],
|
||||
"when": "type=remote"
|
||||
},
|
||||
{
|
||||
"dialog": {
|
||||
"notebook": "./notebooks/edge/deploy-sql-edge-azure.ipynb",
|
||||
"title": "%sql-edge-azure-title%",
|
||||
"name": "sql-edge-azure-dialog",
|
||||
"tabs": [
|
||||
{
|
||||
"title": "",
|
||||
"sections": [
|
||||
{
|
||||
"title": "%azure-info-section-title%",
|
||||
"collapsible": true,
|
||||
"fields": [
|
||||
{
|
||||
"subscriptionVariableName": "AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID",
|
||||
"resourceGroupVariableName": "AZDATA_NB_VAR_ASDE_RESOURCEGROUP",
|
||||
"type": "azure_account",
|
||||
"required": true,
|
||||
"allowNewResourceGroup": true,
|
||||
"newResourceGroupFlagVariableName": "AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP",
|
||||
"newResourceGroupNameVariableName": "AZDATA_NB_VAR_ASDE_NEW_RESOURCEGROUP_NAME"
|
||||
},
|
||||
{
|
||||
"type": "azure_locations",
|
||||
"label": "%azure_location%",
|
||||
"defaultValue": "westus",
|
||||
"required": true,
|
||||
"locationVariableName": "AZDATA_NB_VAR_ASDE_AZURE_LOCATION",
|
||||
"displayLocationVariableName": "AZDATA_NB_VAR_ASDE_AZURE_LOCATION_TEXT",
|
||||
"locations": [
|
||||
"australiaeast",
|
||||
"australiasoutheast",
|
||||
"brazilsouth",
|
||||
"canadacentral",
|
||||
"canadaeast",
|
||||
"centralindia",
|
||||
"centralus",
|
||||
"eastasia",
|
||||
"eastus",
|
||||
"eastus2",
|
||||
"francecentral",
|
||||
"japaneast",
|
||||
"japanwest",
|
||||
"koreacentral",
|
||||
"koreasouth",
|
||||
"northcentralus",
|
||||
"northeurope",
|
||||
"southcentralus",
|
||||
"southindia",
|
||||
"southeastasia",
|
||||
"uksouth",
|
||||
"ukwest",
|
||||
"westcentralus",
|
||||
"westeurope",
|
||||
"westus",
|
||||
"westus2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "%vm_admin%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_VM_ADMIN",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%vm_password%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_VM_PASSWORD",
|
||||
"type": "password",
|
||||
"confirmationRequired": true,
|
||||
"confirmationLabel": "%vm_password_confirm%",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "%sqlserver-info-section-title%",
|
||||
"collapsible": true,
|
||||
"fields": [
|
||||
{
|
||||
"label": "%docker-sql-password-field%",
|
||||
"variableName": "AZDATA_NB_VAR_SA_PASSWORD",
|
||||
"type": "sql_password",
|
||||
"userName": "sa",
|
||||
"confirmationRequired": true,
|
||||
"confirmationLabel": "%docker-confirm-sql-password-field%",
|
||||
"defaultValue": "",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%docker-sql-port-field%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_SQL_PORT",
|
||||
"type": "number",
|
||||
"defaultValue": 31433,
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%dacpac_path%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DACPAC_PATH",
|
||||
"type": "file_picker",
|
||||
"required": false,
|
||||
"filter": {
|
||||
"displayName": "%dacpac-zip-files%",
|
||||
"fileTypes": [
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"requiredTools": [
|
||||
{
|
||||
"name": "azure-cli",
|
||||
"version": "2.9.1"
|
||||
}
|
||||
],
|
||||
"when": "type=azure-create-new"
|
||||
},
|
||||
{
|
||||
"dialog": {
|
||||
"notebook": "./notebooks/edge/deploy-sql-edge-single-device.ipynb",
|
||||
"title": "%sql-edge-azure-single-device-title%",
|
||||
"name": "sql-edge-azure-single-device-dialog",
|
||||
"tabs": [
|
||||
{
|
||||
"title": "",
|
||||
"sections": [
|
||||
{
|
||||
"title": "%azure-info-section-title%",
|
||||
"collapsible": true,
|
||||
"fields": [
|
||||
{
|
||||
"type": "azure_account",
|
||||
"subscriptionVariableName": "AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID",
|
||||
"resourceGroupVariableName": "AZDATA_NB_VAR_ASDE_RESOURCEGROUP",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%iot-hub-name%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_HUBNAME",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%device-id%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DEVICE_ID",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%device-ip-address%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DEVICE_IP_ADDRESS",
|
||||
"type": "text",
|
||||
"description": "%device-ip-address-description%",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "%sqlserver-info-section-title%",
|
||||
"collapsible": true,
|
||||
"fields": [
|
||||
{
|
||||
"label": "%docker-sql-password-field%",
|
||||
"variableName": "AZDATA_NB_VAR_SA_PASSWORD",
|
||||
"type": "sql_password",
|
||||
"userName": "sa",
|
||||
"confirmationRequired": true,
|
||||
"confirmationLabel": "%docker-confirm-sql-password-field%",
|
||||
"defaultValue": "",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%docker-sql-port-field%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_SQL_PORT",
|
||||
"type": "number",
|
||||
"defaultValue": 31433,
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%dacpac_path%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DACPAC_PATH",
|
||||
"type": "file_picker",
|
||||
"required": false,
|
||||
"filter": {
|
||||
"displayName": "%dacpac-zip-files%",
|
||||
"fileTypes": [
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"requiredTools": [
|
||||
{
|
||||
"name": "azure-cli",
|
||||
"version": "2.9.1"
|
||||
}
|
||||
],
|
||||
"when": "type=azure-single-device"
|
||||
},
|
||||
{
|
||||
"dialog": {
|
||||
"notebook": "./notebooks/edge/deploy-sql-edge-multi-device.ipynb",
|
||||
"title": "%sql-edge-azure-multi-device-title%",
|
||||
"name": "sql-edge-azure-multi-device-dialog",
|
||||
"tabs": [
|
||||
{
|
||||
"title": "",
|
||||
"sections": [
|
||||
{
|
||||
"title": "%azure-info-section-title%",
|
||||
"collapsible": true,
|
||||
"fields": [
|
||||
{
|
||||
"type": "azure_account",
|
||||
"subscriptionVariableName": "AZDATA_NB_VAR_ASDE_SUBSCRIPTIONID",
|
||||
"resourceGroupVariableName": "AZDATA_NB_VAR_ASDE_RESOURCEGROUP",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%iot-hub-name%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_HUBNAME",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%device-target-condition%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_TARGET_CONDITION",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "readonly_text",
|
||||
"label": "{0}",
|
||||
"links": [
|
||||
{
|
||||
"text": "%device-target-condition-learn-more%",
|
||||
"url": "https://docs.microsoft.com/azure/iot-edge/module-deployment-monitoring#target-condition"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "%sqlserver-info-section-title%",
|
||||
"collapsible": true,
|
||||
"fields": [
|
||||
{
|
||||
"label": "%docker-sql-password-field%",
|
||||
"variableName": "AZDATA_NB_VAR_SA_PASSWORD",
|
||||
"type": "sql_password",
|
||||
"userName": "sa",
|
||||
"confirmationRequired": true,
|
||||
"confirmationLabel": "%docker-confirm-sql-password-field%",
|
||||
"defaultValue": "",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%docker-sql-port-field%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_SQL_PORT",
|
||||
"type": "number",
|
||||
"defaultValue": 31433,
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"label": "%dacpac_path%",
|
||||
"variableName": "AZDATA_NB_VAR_ASDE_DACPAC_PATH",
|
||||
"type": "file_picker",
|
||||
"required": false,
|
||||
"filter": {
|
||||
"displayName": "%dacpac-zip-files%",
|
||||
"fileTypes": [
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"requiredTools": [
|
||||
{
|
||||
"name": "azure-cli",
|
||||
"version": "2.9.1"
|
||||
}
|
||||
],
|
||||
"when": "type=azure-multi-device"
|
||||
}
|
||||
],
|
||||
"agreement": {
|
||||
@@ -266,7 +576,7 @@
|
||||
},
|
||||
{
|
||||
"text": "%edge-eula%",
|
||||
"url": "https://go.microsoft.com/fwlink/?LinkId=746388"
|
||||
"url": "https://go.microsoft.com/fwlink/?linkid=2128283"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
{
|
||||
"extension-displayName": "Azure SQL DB Edge Deployment Extension",
|
||||
"extension-description": "Provides a notebook-based experience to deploy Azure SQL DB Edge",
|
||||
"extension-displayName": "Azure SQL Edge Deployment Extension",
|
||||
"extension-description": "Provides a notebook-based experience to deploy Azure SQL Edge",
|
||||
"docker-container-name-field": "Container name",
|
||||
"docker-sql-password-field": "SQL Server password",
|
||||
"docker-sql-password-field": "Azure SQL Edge instance (sa) password",
|
||||
"docker-confirm-sql-password-field": "Confirm password",
|
||||
"docker-sql-port-field": "Port",
|
||||
"docker-sql-port-field": "Azure SQL Edge Port",
|
||||
"microsoft-privacy-statement": "Microsoft Privacy Statement",
|
||||
"resource-type-sql-edge-display-name": "Azure SQL DB Edge",
|
||||
"resource-type-sql-edge-description": "Deploy Azure SQL DB Edge (Preview)",
|
||||
"sql-edge-type-display-name": "Type",
|
||||
"sql-edge-local-display-name": "Local",
|
||||
"sql-edge-remote-display-name": "Remote",
|
||||
"sql-edge-local-notebook": "./notebooks/edge/deploy-sql-edge-local.ipynb",
|
||||
"sql-edge-local-title": "Deploy Azure SQL DB Edge locally",
|
||||
"resource-type-sql-edge-display-name": "Azure SQL Edge",
|
||||
"resource-type-sql-edge-description": "Azure SQL Edge (Preview) is an optimized relational database engine geared for IoT and IoT Edge deployments.",
|
||||
"sql-edge-type-display-name": "Deployment target",
|
||||
"sql-edge-local-display-name": "Local container instance",
|
||||
"sql-edge-remote-display-name": "Remote container instance",
|
||||
"sql-edge-local-title": "Deploy Azure SQL Edge container instance on local machine",
|
||||
"docker-settings-section-title": "Docker settings",
|
||||
"docker-registry-field": "Registry",
|
||||
"docker-repository-field": "Repository",
|
||||
@@ -20,11 +19,32 @@
|
||||
"docker-username-field": "Username",
|
||||
"docker-password-field": "Password",
|
||||
"edge-agreement": "I accept {0} and {1}.",
|
||||
"edge-eula": "Microsoft SQL Server License Agreement",
|
||||
"sql-edge-remote-notebook": "./notebooks/edge/deploy-sql-edge-remote.ipynb",
|
||||
"sql-edge-remote-title": "Deploy Azure SQL DB Edge on a remote machine",
|
||||
"edge-eula": "Microsoft Azure SQL Edge License Agreement",
|
||||
"sql-edge-remote-title": "Deploy Azure SQL Edge container instance on remote machine",
|
||||
"remote-info-section-title": "Target machine information",
|
||||
"edge-remote-target-field": "Name or IP address",
|
||||
"edge-remote-username-field": "Username",
|
||||
"edge-remote-password-field": "Password"
|
||||
"edge-remote-password-field": "Password",
|
||||
"sql-edge-azure-display-name": "New Azure IoT Hub and VM",
|
||||
"sql-edge-azure-title": "Deploy Azure SQL Edge to a new Azure VM via IoT hub",
|
||||
"azure_subscription_id": "Subscription id",
|
||||
"azure_resource_group": "Resource group",
|
||||
"azure_location": "Location",
|
||||
"vm_admin": "VM admin username",
|
||||
"vm_password": "VM admin password",
|
||||
"vm_password_confirm": "Confirm VM admin password",
|
||||
"dacpac_path": "Dacpac zip file",
|
||||
"azure-info-section-title": "Azure information",
|
||||
"sqlserver-info-section-title": "Azure SQL Edge information",
|
||||
"dacpac-zip-files": "Dacpac zip files",
|
||||
"sql-edge-azure-single-device-display-name": "Existing device of an Azure IoT Hub",
|
||||
"sql-edge-azure-single-device-title": "Deploy Azure SQL Edge to an existing device",
|
||||
"iot-hub-name": "IoT Hub name",
|
||||
"device-id": "Device ID",
|
||||
"device-ip-address": "Device IP Address",
|
||||
"device-ip-address-description": "Will be used to connect to the Azure SQL Edge instance after deployment",
|
||||
"sql-edge-azure-multi-device-display-name": "Multiple devices of an Azure IoT Hub",
|
||||
"sql-edge-azure-multi-device-title": "Deploy Azure SQL Edge to multiple Azure IoT devices",
|
||||
"device-target-condition": "Target condition",
|
||||
"device-target-condition-learn-more": "Learn more about target condition"
|
||||
}
|
||||
|
||||
1
extensions/azdata/.gitignore
vendored
Normal file
1
extensions/azdata/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.vsix
|
||||
9
extensions/azdata/.vscodeignore
Normal file
9
extensions/azdata/.vscodeignore
Normal file
@@ -0,0 +1,9 @@
|
||||
.gitignore
|
||||
src/**
|
||||
out/**
|
||||
extension.webpack.config.js
|
||||
tsconfig.json
|
||||
yarn.lock
|
||||
coverConfig.json
|
||||
*.vsix
|
||||
coverage
|
||||
21
extensions/azdata/README.md
Normal file
21
extensions/azdata/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Microsoft azdata Extension for Azure Data Studio
|
||||
|
||||
Welcome to Microsoft azdata for Azure Data Studio!
|
||||
|
||||
## Overview
|
||||
|
||||
This extension adds support for azdata within Azure Data Studio.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Privacy Statement
|
||||
|
||||
The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement) describes the privacy statement of this software.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the [Source EULA](https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt).
|
||||
@@ -1,16 +1,21 @@
|
||||
{
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"relativeSourcePath": "..",
|
||||
"relativeCoverageDir": "../../coverage",
|
||||
"ignorePatterns": [
|
||||
"**/node_modules/**"
|
||||
"**/node_modules/**",
|
||||
"**/test/**",
|
||||
"localizedConstants.js",
|
||||
"extension.js"
|
||||
],
|
||||
"reports": [
|
||||
"cobertura"
|
||||
"cobertura",
|
||||
"lcov",
|
||||
"json"
|
||||
],
|
||||
"verbose": false,
|
||||
"remapOptions": {
|
||||
"basePath": ".",
|
||||
"basePath": "..",
|
||||
"useAbsolutePaths": true
|
||||
}
|
||||
}
|
||||
BIN
extensions/azdata/images/extension.png
Normal file
BIN
extensions/azdata/images/extension.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
44
extensions/azdata/package.json
Normal file
44
extensions/azdata/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "azdata",
|
||||
"displayName": "%azdata.displayName%",
|
||||
"description": "%azdata.description%",
|
||||
"version": "0.1.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||
"icon": "images/extension.png",
|
||||
"engines": {
|
||||
"vscode": "*",
|
||||
"azdata": ">=1.20.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/azuredatastudio.git"
|
||||
},
|
||||
"main": "./out/extension",
|
||||
"dependencies": {
|
||||
"request": "^2.88.2",
|
||||
"sudo-prompt": "^9.2.1",
|
||||
"vscode-nls": "^4.1.2",
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/request": "^2.48.5",
|
||||
"@types/sinon": "^9.0.4",
|
||||
"@types/uuid": "^8.0.0",
|
||||
"@types/which": "^1.3.2",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"nock": "^13.0.2",
|
||||
"should": "^13.2.3",
|
||||
"sinon": "^9.0.2",
|
||||
"typemoq": "^2.1.0",
|
||||
"vscodetestcover": "^1.0.9"
|
||||
}
|
||||
}
|
||||
4
extensions/azdata/package.nls.json
Normal file
4
extensions/azdata/package.nls.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"azdata.displayName": "azdata",
|
||||
"azdata.description": "Support for azdata"
|
||||
}
|
||||
142
extensions/azdata/src/azdata.ts
Normal file
142
extensions/azdata/src/azdata.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as vscode from 'vscode';
|
||||
import { HttpClient } from './common/httpClient';
|
||||
import * as loc from './localizedConstants';
|
||||
import { executeCommand, executeSudoCommand } from './common/childProcess';
|
||||
import { searchForCmd } from './common/utils';
|
||||
|
||||
export const azdataHostname = 'https://aka.ms';
|
||||
export const azdataUri = 'azdata-msi';
|
||||
/**
|
||||
* Information about an azdata installation
|
||||
*/
|
||||
export interface IAzdata {
|
||||
path: string,
|
||||
version: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the existing installation of azdata, or throws an error if it couldn't find it
|
||||
* or encountered an unexpected error.
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
export async function findAzdata(outputChannel: vscode.OutputChannel): Promise<IAzdata> {
|
||||
outputChannel.appendLine(loc.searchingForAzdata);
|
||||
try {
|
||||
let azdata: IAzdata | undefined = undefined;
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
azdata = await findAzdataWin32(outputChannel);
|
||||
break;
|
||||
default:
|
||||
azdata = await findSpecificAzdata('azdata', outputChannel);
|
||||
}
|
||||
outputChannel.appendLine(loc.foundExistingAzdata(azdata.path, azdata.version));
|
||||
return azdata;
|
||||
} catch (err) {
|
||||
outputChannel.appendLine(loc.couldNotFindAzdata(err));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the appropriate installer and/or runs the command to install azdata
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
export async function downloadAndInstallAzdata(outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
const statusDisposable = vscode.window.setStatusBarMessage(loc.installingAzdata);
|
||||
outputChannel.show();
|
||||
outputChannel.appendLine(loc.installingAzdata);
|
||||
try {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await downloadAndInstallAzdataWin32(outputChannel);
|
||||
break;
|
||||
case 'darwin':
|
||||
await installAzdataDarwin(outputChannel);
|
||||
break;
|
||||
case 'linux':
|
||||
await installAzdataLinux(outputChannel);
|
||||
break;
|
||||
default:
|
||||
throw new Error(loc.platformUnsupported(process.platform));
|
||||
}
|
||||
} finally {
|
||||
statusDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the Windows installer and runs it
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
async function downloadAndInstallAzdataWin32(outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
const downloadFolder = os.tmpdir();
|
||||
const downloadedFile = await HttpClient.download(`${azdataHostname}/${azdataUri}`, downloadFolder, outputChannel);
|
||||
await executeCommand('msiexec', ['/qn', '/i', downloadedFile], outputChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs commands to install azdata on MacOS
|
||||
*/
|
||||
async function installAzdataDarwin(outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
await executeCommand('brew', ['tap', 'microsoft/azdata-cli-release'], outputChannel);
|
||||
await executeCommand('brew', ['update'], outputChannel);
|
||||
await executeCommand('brew', ['install', 'azdata-cli'], outputChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs commands to install azdata on Linux
|
||||
*/
|
||||
async function installAzdataLinux(outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
// https://docs.microsoft.com/en-us/sql/big-data-cluster/deploy-install-azdata-linux-package
|
||||
// Get packages needed for install process
|
||||
await executeSudoCommand('apt-get update', outputChannel);
|
||||
await executeSudoCommand('apt-get install gnupg ca-certificates curl wget software-properties-common apt-transport-https lsb-release -y', outputChannel);
|
||||
// Download and install the signing key
|
||||
await executeSudoCommand('curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc.gpg > /dev/null', outputChannel);
|
||||
// Add the azdata repository information
|
||||
const release = (await executeCommand('lsb_release', ['-rs'], outputChannel)).stdout.trim();
|
||||
await executeSudoCommand(`add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/${release}/mssql-server-2019.list)"`, outputChannel);
|
||||
// Update repository information and install azdata
|
||||
await executeSudoCommand('apt-get update', outputChannel);
|
||||
await executeSudoCommand('apt-get install -y azdata-cli', outputChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds azdata specifically on Windows
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
async function findAzdataWin32(outputChannel: vscode.OutputChannel): Promise<IAzdata> {
|
||||
const promise = searchForCmd('azdata.cmd');
|
||||
return findSpecificAzdata(await promise, outputChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version using a known azdata path
|
||||
* @param path The path to the azdata executable
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
async function findSpecificAzdata(path: string, outputChannel: vscode.OutputChannel): Promise<IAzdata> {
|
||||
const versionOutput = await executeCommand(path, ['--version'], outputChannel);
|
||||
return {
|
||||
path: path,
|
||||
version: parseVersion(versionOutput.stdout)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses out the azdata version from the raw azdata version output
|
||||
* @param raw The raw version output from azdata --version
|
||||
*/
|
||||
function parseVersion(raw: string): string {
|
||||
// Currently the version is a multi-line string that contains other version information such
|
||||
// as the Python installation, with the first line being the version of azdata itself.
|
||||
const lines = raw.split(os.EOL);
|
||||
return lines[0].trim();
|
||||
}
|
||||
84
extensions/azdata/src/common/childProcess.ts
Normal file
84
extensions/azdata/src/common/childProcess.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as cp from 'child_process';
|
||||
import * as sudo from 'sudo-prompt';
|
||||
import * as loc from '../localizedConstants';
|
||||
|
||||
/**
|
||||
* Wrapper error for when an unexpected exit code was received
|
||||
*/
|
||||
export class ExitCodeError extends Error {
|
||||
constructor(public code: number) {
|
||||
super(loc.unexpectedExitCode(code));
|
||||
}
|
||||
}
|
||||
|
||||
export type ProcessOutput = { stdout: string, stderr: string };
|
||||
|
||||
/**
|
||||
* Executes the specified command. Throws an error for a non-0 exit code or if stderr receives output
|
||||
* @param command The command to execute
|
||||
* @param args Optional args to pass, every arg and arg value must be a separate item in the array
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
export async function executeCommand(command: string, args: string[], outputChannel: vscode.OutputChannel): Promise<ProcessOutput> {
|
||||
return new Promise((resolve, reject) => {
|
||||
outputChannel.appendLine(loc.executingCommand(command, args));
|
||||
const stdoutBuffers: Buffer[] = [];
|
||||
const stderrBuffers: Buffer[] = [];
|
||||
const child = cp.spawn(command, args, { shell: true });
|
||||
child.stdout.on('data', (b: Buffer) => stdoutBuffers.push(b));
|
||||
child.stderr.on('data', (b: Buffer) => stderrBuffers.push(b));
|
||||
child.on('error', reject);
|
||||
child.on('exit', code => {
|
||||
const stdout = Buffer.concat(stdoutBuffers).toString('utf8').trim();
|
||||
const stderr = Buffer.concat(stderrBuffers).toString('utf8').trim();
|
||||
if (stdout) {
|
||||
outputChannel.appendLine(loc.stdoutOutput(stdout));
|
||||
}
|
||||
if (stderr) {
|
||||
outputChannel.appendLine(loc.stdoutOutput(stderr));
|
||||
}
|
||||
if (code) {
|
||||
const err = new ExitCodeError(code);
|
||||
outputChannel.appendLine(err.message);
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({ stdout: stdout, stderr: stderr });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a command with admin privileges. The user will be prompted to enter credentials for invocation of
|
||||
* this function. The exact prompt is platform-dependent.
|
||||
* @param command The command to execute
|
||||
* @param args The additional args
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
export async function executeSudoCommand(command: string, outputChannel: vscode.OutputChannel): Promise<ProcessOutput> {
|
||||
return new Promise((resolve, reject) => {
|
||||
outputChannel.appendLine(loc.executingCommand(`sudo ${command}`, []));
|
||||
sudo.exec(command, { name: vscode.env.appName }, (error, stdout, stderr) => {
|
||||
stdout = stdout?.toString() ?? '';
|
||||
stderr = stderr?.toString() ?? '';
|
||||
if (stdout) {
|
||||
outputChannel.appendLine(loc.stdoutOutput(stdout));
|
||||
}
|
||||
if (stderr) {
|
||||
outputChannel.appendLine(loc.stdoutOutput(stderr));
|
||||
}
|
||||
if (error) {
|
||||
outputChannel.appendLine(loc.unexpectedCommandError(error.message));
|
||||
reject(error);
|
||||
} else {
|
||||
resolve({ stdout: stdout, stderr: stderr });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
96
extensions/azdata/src/common/httpClient.ts
Normal file
96
extensions/azdata/src/common/httpClient.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as request from 'request';
|
||||
import * as path from 'path';
|
||||
import * as loc from '../localizedConstants';
|
||||
|
||||
const DownloadTimeout = 20000;
|
||||
|
||||
export namespace HttpClient {
|
||||
|
||||
/**
|
||||
* Downloads a file from the given URL, resolving to the full path of the downloaded file when complete
|
||||
* @param downloadUrl The URL to download the file from
|
||||
* @param targetFolder The folder to download the file to
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
* @returns Full path to the downloaded file
|
||||
*/
|
||||
export function download(downloadUrl: string, targetFolder: string, outputChannel: vscode.OutputChannel): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let totalMegaBytes: number | undefined = undefined;
|
||||
let receivedBytes = 0;
|
||||
let printThreshold = 0.1;
|
||||
let downloadRequest = request.get(downloadUrl, { timeout: DownloadTimeout })
|
||||
.on('error', downloadError => {
|
||||
outputChannel.appendLine(loc.downloadError);
|
||||
outputChannel.appendLine(downloadError?.message ?? downloadError);
|
||||
reject(downloadError);
|
||||
})
|
||||
.on('response', (response) => {
|
||||
if (response.statusCode !== 200) {
|
||||
outputChannel.appendLine(loc.downloadError);
|
||||
outputChannel.appendLine(response.statusMessage);
|
||||
return reject(response.statusMessage);
|
||||
}
|
||||
const filename = path.basename(response.request.path);
|
||||
const targetPath = path.join(targetFolder, filename);
|
||||
outputChannel.appendLine(loc.downloadingTo(filename, targetPath));
|
||||
// Wait to create the WriteStream until here so we can use the actual
|
||||
// filename based off of the URI.
|
||||
downloadRequest.pipe(fs.createWriteStream(targetPath))
|
||||
.on('close', async () => {
|
||||
outputChannel.appendLine(loc.downloadFinished);
|
||||
resolve(targetPath);
|
||||
})
|
||||
.on('error', (downloadError) => {
|
||||
reject(downloadError);
|
||||
downloadRequest.abort();
|
||||
});
|
||||
let contentLength = response.headers['content-length'];
|
||||
let totalBytes = parseInt(contentLength || '0');
|
||||
totalMegaBytes = totalBytes / (1024 * 1024);
|
||||
outputChannel.appendLine(loc.downloadingProgressMb('0', totalMegaBytes.toFixed(2)));
|
||||
})
|
||||
.on('data', (data) => {
|
||||
receivedBytes += data.length;
|
||||
if (totalMegaBytes) {
|
||||
let receivedMegaBytes = receivedBytes / (1024 * 1024);
|
||||
let percentage = receivedMegaBytes / totalMegaBytes;
|
||||
if (percentage >= printThreshold) {
|
||||
outputChannel.appendLine(loc.downloadingProgressMb(receivedMegaBytes.toFixed(2), totalMegaBytes.toFixed(2)));
|
||||
printThreshold += 0.1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename for the specified URL - following redirects as needed
|
||||
* @param url The URL to get the filename of
|
||||
*/
|
||||
export async function getFilename(url: string, outputChannel: vscode.OutputChannel): Promise<string> {
|
||||
outputChannel.appendLine(loc.gettingFilenameOfUrl(url));
|
||||
return new Promise((resolve, reject) => {
|
||||
let httpRequest = request.get(url, { timeout: DownloadTimeout })
|
||||
.on('error', downloadError => {
|
||||
reject(downloadError);
|
||||
})
|
||||
.on('response', (response) => {
|
||||
if (response.statusCode !== 200) {
|
||||
return reject(response.statusMessage);
|
||||
}
|
||||
// We don't want to actually download the file so abort the request now
|
||||
httpRequest.abort();
|
||||
const filename = path.basename(response.request.path);
|
||||
outputChannel.appendLine(loc.gotFilenameOfUrl(response.request.path, filename));
|
||||
resolve(filename);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
25
extensions/azdata/src/common/promise.ts
Normal file
25
extensions/azdata/src/common/promise.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Deferred promise
|
||||
*/
|
||||
export class Deferred<T> {
|
||||
promise: Promise<T>;
|
||||
resolve!: (value?: T | PromiseLike<T>) => void;
|
||||
reject!: (reason?: any) => void;
|
||||
constructor() {
|
||||
this.promise = new Promise<T>((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
});
|
||||
}
|
||||
|
||||
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
|
||||
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
|
||||
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult> {
|
||||
return this.promise.then(onfulfilled, onrejected);
|
||||
}
|
||||
}
|
||||
15
extensions/azdata/src/common/utils.ts
Normal file
15
extensions/azdata/src/common/utils.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as which from 'which';
|
||||
|
||||
/**
|
||||
* Searches for the first instance of the specified executable in the PATH environment variable
|
||||
* @param exe The executable to search for
|
||||
*/
|
||||
export function searchForCmd(exe: string): Promise<string> {
|
||||
// Note : This is separated out to allow for easy test stubbing
|
||||
return new Promise<string>((resolve, reject) => which(exe, (err, path) => err ? reject(err) : resolve(path)));
|
||||
}
|
||||
42
extensions/azdata/src/extension.ts
Normal file
42
extensions/azdata/src/extension.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { findAzdata } from './azdata';
|
||||
|
||||
export async function activate(): Promise<void> {
|
||||
const outputChannel = vscode.window.createOutputChannel('azdata');
|
||||
await checkForAzdata(outputChannel);
|
||||
}
|
||||
|
||||
async function checkForAzdata(outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
try {
|
||||
await findAzdata(outputChannel);
|
||||
} catch (err) {
|
||||
// Don't block on this since we want the extension to finish activating without needing user input.
|
||||
// Calls will be made to handle azdata not being installed
|
||||
promptToInstallAzdata(outputChannel).catch(e => console.log(`Unexpected error prompting to install azdata ${e}`));
|
||||
}
|
||||
}
|
||||
|
||||
async function promptToInstallAzdata(_outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
//TODO: Figure out better way to display/prompt
|
||||
/*
|
||||
const response = await vscode.window.showErrorMessage(loc.couldNotFindAzdataWithPrompt, loc.install, loc.cancel);
|
||||
if (response === loc.install) {
|
||||
try {
|
||||
await downloadAndInstallAzdata(outputChannel);
|
||||
vscode.window.showInformationMessage(loc.azdataInstalled);
|
||||
} catch (err) {
|
||||
// Windows: 1602 is User Cancelling installation - not unexpected so don't display
|
||||
if (!(err instanceof ExitCodeError) || err.code !== 1602) {
|
||||
vscode.window.showWarningMessage(loc.installError(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
export function deactivate(): void { }
|
||||
30
extensions/azdata/src/localizedConstants.ts
Normal file
30
extensions/azdata/src/localizedConstants.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export const searchingForAzdata = localize('azdata.searchingForAzdata', "Searching for existing azdata installation...");
|
||||
export function foundExistingAzdata(path: string, version: string): string { return localize('azdata.foundExistingAzdata', "Found existing azdata installation at {0} (v{1})", path, version); }
|
||||
export function downloadingProgressMb(currentMb: string, totalMb: string): string { return localize('azdata.downloadingProgressMb', "Downloading ({0} / {1} MB)", currentMb, totalMb); }
|
||||
export const downloadFinished = localize('azdata.downloadFinished', "Download finished");
|
||||
export const install = localize('azdata.install', "Install");
|
||||
export const installingAzdata = localize('azdata.installingAzdata', "Installing azdata...");
|
||||
export const azdataInstalled = localize('azdata.azdataInstalled', "azdata was successfully installed. Restarting Azure Data Studio is required to complete configuration - features will not be activated until this is done.");
|
||||
export const cancel = localize('azdata.cancel', "Cancel");
|
||||
export function downloadingTo(name: string, location: string): string { return localize('azdata.downloadingTo', "Downloading {0} to {1}", name, location); }
|
||||
export function executingCommand(command: string, args: string[]): string { return localize('azdata.executingCommand', "Executing command \"{0} {1}\"", command, args?.join(' ')); }
|
||||
export function stdoutOutput(stdout: string): string { return localize('azdat.stdoutOutput', "stdout : {0}", stdout); }
|
||||
export function stderrOutput(stderr: string): string { return localize('azdat.stderrOutput', "stderr : {0}", stderr); }
|
||||
export function gettingFilenameOfUrl(url: string): string { return localize('azdata.gettingFilenameOfUrl', "Getting filename of resource at URL {0}", url); }
|
||||
export function gotFilenameOfUrl(url: string, filename: string): string { return localize('azdata.gotFilenameOfUrl', "Got filename {0} from URL {1}", filename, url); }
|
||||
|
||||
export function couldNotFindAzdata(err: any): string { return localize('azdata.couldNotFindAzdata', "Could not find azdata. Error : {0}", err.message ?? err); }
|
||||
export const couldNotFindAzdataWithPrompt = localize('azdata.couldNotFindAzdataWithPrompt', "Could not find azdata, install it now? If not then some features will not be able to function.");
|
||||
export const downloadError = localize('azdata.downloadError', "Error while downloading");
|
||||
export function installError(err: any): string { return localize('azdata.installError', "Error installing azdata : {0}", err.message ?? err); }
|
||||
export function platformUnsupported(platform: string): string { return localize('azdata.platformUnsupported', "Platform '{0}' is currently unsupported", platform); }
|
||||
export function unexpectedCommandError(errMsg: string): string { return localize('azdata.unexpectedCommandError', "Unexpected error executing command : {0}", errMsg); }
|
||||
export function unexpectedExitCode(code: number): string { return localize('azdata.unexpectedExitCode', "Unexpected exit code from command : {0}", code); }
|
||||
68
extensions/azdata/src/test/azdata.test.ts
Normal file
68
extensions/azdata/src/test/azdata.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as azdata from '../azdata';
|
||||
import * as sinon from 'sinon';
|
||||
import * as childProcess from '../common/childProcess';
|
||||
import * as should from 'should';
|
||||
import * as utils from '../common/utils';
|
||||
import * as nock from 'nock';
|
||||
|
||||
describe('azdata', function () {
|
||||
|
||||
let outputChannelMock: TypeMoq.IMock<vscode.OutputChannel>;
|
||||
beforeEach(function (): void {
|
||||
outputChannelMock = TypeMoq.Mock.ofType<vscode.OutputChannel>();
|
||||
|
||||
});
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
nock.cleanAll();
|
||||
nock.enableNetConnect();
|
||||
});
|
||||
|
||||
describe('findAzdata', function () {
|
||||
it('successful', async function (): Promise<void> {
|
||||
if (process.platform === 'win32') {
|
||||
// Mock searchForCmd to return a path to azdata.cmd
|
||||
sinon.stub(utils, 'searchForCmd').returns(Promise.resolve('C:\\path\\to\\azdata.cmd'));
|
||||
}
|
||||
// Mock call to --version to simulate azdata being installed
|
||||
sinon.stub(childProcess, 'executeCommand').returns(Promise.resolve({ stdout: 'v1.0.0', stderr: '' }));
|
||||
await should(azdata.findAzdata(outputChannelMock.object)).not.be.rejected();
|
||||
});
|
||||
it('unsuccessful', async function (): Promise<void> {
|
||||
if (process.platform === 'win32') {
|
||||
// Mock searchForCmd to return a failure to find azdata.cmd
|
||||
sinon.stub(utils, 'searchForCmd').returns(Promise.reject(new Error('Could not find azdata')));
|
||||
} else {
|
||||
// Mock call to executeCommand to simulate azdata --version returning error
|
||||
sinon.stub(childProcess, 'executeCommand').returns(Promise.reject({ stdout: '', stderr: 'command not found: azdata' }));
|
||||
}
|
||||
await should(azdata.findAzdata(outputChannelMock.object)).be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Install not implemented on linux yet
|
||||
describe.skip('downloadAndInstallAzdata', function (): void {
|
||||
it('successful download & install', async function (): Promise<void> {
|
||||
nock(azdata.azdataHostname)
|
||||
.get(`/${azdata.azdataUri}`)
|
||||
.replyWithFile(200, __filename);
|
||||
const downloadPromise = azdata.downloadAndInstallAzdata(outputChannelMock.object);
|
||||
await downloadPromise;
|
||||
});
|
||||
|
||||
it('errors on unsuccessful download', async function (): Promise<void> {
|
||||
nock('https://aka.ms')
|
||||
.get('/azdata-msi')
|
||||
.reply(404);
|
||||
const downloadPromise = azdata.downloadAndInstallAzdata(outputChannelMock.object);
|
||||
await should(downloadPromise).be.rejected();
|
||||
});
|
||||
});
|
||||
});
|
||||
30
extensions/azdata/src/test/common/childProcess.test.ts
Normal file
30
extensions/azdata/src/test/common/childProcess.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { executeCommand } from '../../common/childProcess';
|
||||
|
||||
describe('ChildProcess', function () {
|
||||
const outputChannelMock = TypeMoq.Mock.ofType<vscode.OutputChannel>();
|
||||
|
||||
[[], ['test']].forEach(args => {
|
||||
it(`Output channel is used with ${JSON.stringify(args)} args`, async function (): Promise<void> {
|
||||
await executeCommand('echo', args, outputChannelMock.object);
|
||||
outputChannelMock.verify(x => x.appendLine(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
|
||||
});
|
||||
});
|
||||
|
||||
it('Gets expected output', async function (): Promise<void> {
|
||||
const echoOutput = 'test';
|
||||
const output = await executeCommand('echo', [echoOutput], outputChannelMock.object);
|
||||
should(output.stdout).equal(echoOutput);
|
||||
});
|
||||
|
||||
it('Invalid command errors', async function (): Promise<void> {
|
||||
await should(executeCommand('invalid_command', [], outputChannelMock.object)).be.rejected();
|
||||
});
|
||||
});
|
||||
114
extensions/azdata/src/test/common/httpClient.test.ts
Normal file
114
extensions/azdata/src/test/common/httpClient.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { HttpClient } from '../../common/httpClient';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as nock from 'nock';
|
||||
import * as sinon from 'sinon';
|
||||
import { PassThrough } from 'stream';
|
||||
import { Deferred } from '../../common/promise';
|
||||
|
||||
describe('HttpClient', function (): void {
|
||||
|
||||
let outputChannelMock: TypeMoq.IMock<vscode.OutputChannel>;
|
||||
|
||||
before(function (): void {
|
||||
outputChannelMock = TypeMoq.Mock.ofType<vscode.OutputChannel>();
|
||||
});
|
||||
|
||||
afterEach(function (): void {
|
||||
nock.cleanAll();
|
||||
nock.enableNetConnect();
|
||||
});
|
||||
|
||||
describe('download', function(): void {
|
||||
it('downloads file successfully', async function (): Promise<void> {
|
||||
nock('https://127.0.0.1')
|
||||
.get('/README.md')
|
||||
.replyWithFile(200, __filename);
|
||||
const downloadFolder = os.tmpdir();
|
||||
const downloadPath = await HttpClient.download('https://127.0.0.1/README.md', downloadFolder, outputChannelMock.object);
|
||||
// Verify file was downloaded correctly
|
||||
await fs.promises.stat(downloadPath);
|
||||
});
|
||||
|
||||
it('errors on response stream error', async function (): Promise<void> {
|
||||
const downloadFolder = os.tmpdir();
|
||||
nock('https://127.0.0.1')
|
||||
.get('/')
|
||||
.replyWithError('Unexpected Error');
|
||||
const downloadPromise = HttpClient.download('https://127.0.0.1', downloadFolder, outputChannelMock.object);
|
||||
|
||||
await should(downloadPromise).be.rejected();
|
||||
});
|
||||
|
||||
it('rejects on non-OK status code', async function (): Promise<void> {
|
||||
const downloadFolder = os.tmpdir();
|
||||
nock('https://127.0.0.1')
|
||||
.get('/')
|
||||
.reply(404, '');
|
||||
const downloadPromise = HttpClient.download('https://127.0.0.1', downloadFolder, outputChannelMock.object);
|
||||
|
||||
await should(downloadPromise).be.rejected();
|
||||
});
|
||||
|
||||
it('errors on write stream error', async function (): Promise<void> {
|
||||
const downloadFolder = os.tmpdir();
|
||||
const mockWriteStream = new PassThrough();
|
||||
const deferredPromise = new Deferred();
|
||||
sinon.stub(fs, 'createWriteStream').callsFake(() => {
|
||||
deferredPromise.resolve();
|
||||
return <any>mockWriteStream;
|
||||
});
|
||||
nock('https://127.0.0.1')
|
||||
.get('/')
|
||||
.reply(200, '');
|
||||
const downloadPromise = HttpClient.download('https://127.0.0.1', downloadFolder, outputChannelMock.object);
|
||||
// Wait for the stream to be created before throwing the error or HttpClient will miss the event
|
||||
await deferredPromise;
|
||||
try {
|
||||
// Passthrough streams will throw the error we emit so just no-op and
|
||||
// let the HttpClient handler handle the error
|
||||
mockWriteStream.emit('error', 'Unexpected write error');
|
||||
} catch (err) { }
|
||||
await should(downloadPromise).be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFilename', function(): void {
|
||||
it('Gets filename correctly', async function (): Promise<void> {
|
||||
const filename = 'azdata-cli-20.0.0.msi';
|
||||
nock('https://127.0.0.1')
|
||||
.get(`/${filename}`)
|
||||
.reply(200);
|
||||
const receivedFilename = await HttpClient.getFilename(`https://127.0.0.1/${filename}`, outputChannelMock.object);
|
||||
|
||||
should(receivedFilename).equal(filename);
|
||||
});
|
||||
|
||||
it('errors on response error', async function (): Promise<void> {
|
||||
nock('https://127.0.0.1')
|
||||
.get('/')
|
||||
.replyWithError('Unexpected Error');
|
||||
const getFilenamePromise = HttpClient.getFilename('https://127.0.0.1', outputChannelMock.object);
|
||||
|
||||
await should(getFilenamePromise).be.rejected();
|
||||
});
|
||||
|
||||
it('rejects on non-OK status code', async function (): Promise<void> {
|
||||
nock('https://127.0.0.1')
|
||||
.get('/')
|
||||
.reply(404, '');
|
||||
const getFilenamePromise = HttpClient.getFilename('https://127.0.0.1', outputChannelMock.object);
|
||||
|
||||
await should(getFilenamePromise).be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
30
extensions/azdata/src/test/common/promise.test.ts
Normal file
30
extensions/azdata/src/test/common/promise.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import { Deferred } from '../../common/promise';
|
||||
|
||||
describe('DeferredPromise', function (): void {
|
||||
|
||||
it('Resolves correctly', async function(): Promise<void> {
|
||||
const deferred = new Deferred();
|
||||
deferred.resolve();
|
||||
await should(deferred.promise).be.resolved();
|
||||
});
|
||||
|
||||
it('Rejects correctly', async function(): Promise<void> {
|
||||
const deferred = new Deferred();
|
||||
deferred.reject();
|
||||
await should(deferred.promise).be.rejected();
|
||||
});
|
||||
|
||||
it('Chains then correctly', function(done): void {
|
||||
const deferred = new Deferred();
|
||||
deferred.then( () => {
|
||||
done();
|
||||
});
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
18
extensions/azdata/src/test/common/utils.test.ts
Normal file
18
extensions/azdata/src/test/common/utils.test.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import { searchForCmd as searchForExe } from '../../common/utils';
|
||||
|
||||
describe('utils', function () {
|
||||
describe('searchForExe', function(): void {
|
||||
it('finds exe successfully', async function(): Promise<void> {
|
||||
await searchForExe('node');
|
||||
});
|
||||
it('throws for non-existent exe', async function(): Promise<void> {
|
||||
await should(searchForExe('someFakeExe')).be.rejected();
|
||||
});
|
||||
});
|
||||
});
|
||||
48
extensions/azdata/src/test/index.ts
Normal file
48
extensions/azdata/src/test/index.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
const testRunner = require('vscodetestcover');
|
||||
|
||||
const suite = 'azdata Extension Tests';
|
||||
|
||||
const mochaOptions: any = {
|
||||
ui: 'bdd',
|
||||
useColors: true,
|
||||
timeout: 10000
|
||||
};
|
||||
|
||||
// set relevant mocha options from the environment
|
||||
if (process.env.ADS_TEST_GREP) {
|
||||
mochaOptions.grep = process.env.ADS_TEST_GREP;
|
||||
console.log(`setting options.grep to: ${mochaOptions.grep}`);
|
||||
}
|
||||
if (process.env.ADS_TEST_INVERT_GREP) {
|
||||
mochaOptions.invert = parseInt(process.env.ADS_TEST_INVERT_GREP);
|
||||
console.log(`setting options.invert to: ${mochaOptions.invert}`);
|
||||
}
|
||||
if (process.env.ADS_TEST_TIMEOUT) {
|
||||
mochaOptions.timeout = parseInt(process.env.ADS_TEST_TIMEOUT);
|
||||
console.log(`setting options.timeout to: ${mochaOptions.timeout}`);
|
||||
}
|
||||
if (process.env.ADS_TEST_RETRIES) {
|
||||
mochaOptions.retries = parseInt(process.env.ADS_TEST_RETRIES);
|
||||
console.log(`setting options.retries to: ${mochaOptions.retries}`);
|
||||
}
|
||||
|
||||
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
|
||||
mochaOptions.reporter = 'mocha-multi-reporters';
|
||||
mochaOptions.reporterOptions = {
|
||||
reporterEnabled: 'spec, mocha-junit-reporter',
|
||||
mochaJunitReporterReporterOptions: {
|
||||
testsuitesTitle: `${suite} ${process.platform}`,
|
||||
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testRunner.configure(mochaOptions, { coverConfig: '../../coverConfig.json' });
|
||||
|
||||
export = testRunner;
|
||||
@@ -3,6 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/sql/azdata.d.ts'/>
|
||||
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
|
||||
/// <reference path="../../../types/lib.textEncoder.d.ts" />
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"outDir": "./out",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
],
|
||||
"outDir": "./out"
|
||||
"es6",
|
||||
"es2015.promise"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
1289
extensions/azdata/yarn.lock
Normal file
1289
extensions/azdata/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user