mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
087a6a0810 | ||
|
|
495b4ee7c2 | ||
|
|
7833c28b7a | ||
|
|
bbfb68b082 | ||
|
|
b32e7a777c | ||
|
|
a327889d05 | ||
|
|
5ac89e5a49 | ||
|
|
849653927a | ||
|
|
3545483fc1 | ||
|
|
e5a1896414 | ||
|
|
bec8e72688 | ||
|
|
86748e6d69 | ||
|
|
596f09f754 | ||
|
|
563e25f073 | ||
|
|
1800d0baaf | ||
|
|
2182658301 | ||
|
|
3990719054 | ||
|
|
071b510fba | ||
|
|
d2d2ade9f7 | ||
|
|
d97d2e5c91 | ||
|
|
a6ba44e435 | ||
|
|
4967e630fb | ||
|
|
2508464fde | ||
|
|
782623cba9 | ||
|
|
36045c5381 | ||
|
|
7e49167530 | ||
|
|
a680a2a7dc | ||
|
|
4734451f5f | ||
|
|
dafb780987 | ||
|
|
5fba3e31b4 | ||
|
|
0315020cf0 | ||
|
|
6dca896768 | ||
|
|
90454fbe87 | ||
|
|
f9b2136494 | ||
|
|
3d1c1aefb3 | ||
|
|
e6a65599fd | ||
|
|
32ac907403 | ||
|
|
3af05d62b2 | ||
|
|
b5d8dfa509 | ||
|
|
612987d1e5 | ||
|
|
916598e029 | ||
|
|
c45c634938 | ||
|
|
1bed0d0733 | ||
|
|
e0075b7633 | ||
|
|
0029767561 | ||
|
|
93f9828d04 | ||
|
|
c484af0901 | ||
|
|
b2a96bbe50 | ||
|
|
2414f43757 | ||
|
|
22c54a9917 | ||
|
|
a14c0351ba | ||
|
|
31f75a46c8 | ||
|
|
08d1e9cd73 | ||
|
|
0da83b5d4b | ||
|
|
37d7266751 | ||
|
|
ddfb61b46a | ||
|
|
9a2e8cffed | ||
|
|
e9299d1991 | ||
|
|
08d97cc795 |
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
@@ -9,7 +8,7 @@
|
||||
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
|
||||
"stopOnEntry": true,
|
||||
"args": [
|
||||
"watch-extension:json-client"
|
||||
"hygiene"
|
||||
],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
@@ -87,6 +86,9 @@
|
||||
"runtimeArgs": [
|
||||
"--inspect=5875"
|
||||
],
|
||||
"skipFiles": [
|
||||
"**/winjs*.js"
|
||||
],
|
||||
"webRoot": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
|
||||
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -10,6 +10,9 @@
|
||||
"when": "$(basename).ts"
|
||||
}
|
||||
},
|
||||
"files.associations": {
|
||||
"OSSREADME.json": "jsonc"
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/bower_components": true,
|
||||
@@ -35,6 +38,5 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
||||
# Change Log
|
||||
|
||||
## Version 0.27.3
|
||||
* Release date: March 28, 2017
|
||||
* Release status: Public Preview
|
||||
|
||||
## What's new in this version
|
||||
The March Public Preview release enables some key aspects of the SQL Operations
|
||||
Studio extensibility story. Here are some highlights in this release.
|
||||
|
||||
* Enhance the Manage Dashboard extensibility model to support tabbed Insights and Configuration panes
|
||||
* Dashboard Insights extensions for `sp_whoisactive` from [whoisactive.com](http://whoisactive.com)
|
||||
* Extension Manager enables simple acquisition of 1st-party and 3rd-party extensions
|
||||
* Add additional Extensibility APIs for `connection` and `objectexplorer` management
|
||||
* Community Localization open for 10 languages
|
||||
* Continue to fix important customer impacting GitHub issues
|
||||
|
||||
## Version 0.26.7
|
||||
* Release date: February 16, 2017
|
||||
* Release status: Public Preview Hotfix 1
|
||||
|
||||
20
README.md
20
README.md
@@ -4,16 +4,16 @@
|
||||
|
||||
SQL Operations Studio is a data management tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
|
||||
|
||||
**Download SQL Operations Studio February Public Preview**
|
||||
**Download SQL Operations Studio March Public Preview**
|
||||
|
||||
Platform | Link
|
||||
-- | --
|
||||
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=867998
|
||||
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=867997
|
||||
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=867999
|
||||
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=868000
|
||||
Linux DEB | https://go.microsoft.com/fwlink/?linkid=868002
|
||||
Linux RPM | https://go.microsoft.com/fwlink/?linkid=868001
|
||||
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=870837
|
||||
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=870838
|
||||
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=870839
|
||||
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=870840
|
||||
Linux DEB | https://go.microsoft.com/fwlink/?linkid=870842
|
||||
Linux RPM | https://go.microsoft.com/fwlink/?linkid=870841
|
||||
|
||||
Go to our [download page](https://aka.ms/sqlopsstudio) for more specific instructions.
|
||||
|
||||
@@ -69,6 +69,8 @@ The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.micro
|
||||
## Contributions and "thank you"
|
||||
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
|
||||
|
||||
* westerncj for `Removed duplicate contribution from README.md (#753)`
|
||||
* ntovas for `Fix for duplicate extensions shown in "Save File" dialog. (#779)`
|
||||
* SebastianPfliegel for `Add cursor snippet (#475)`
|
||||
* mikaoelitiana for fix: `revert README and CONTRIBUTING after last VSCode merge (#574)`
|
||||
* alextercete for `Reinstate menu item to install from VSIX (#682)`
|
||||
@@ -79,6 +81,10 @@ We would like to thank all our users who raised issues, and in particular the fo
|
||||
* stebet for `Fix #153: Fixing sql snippets that failed on a DB with case-sensitive collation. (#152)`
|
||||
* SebastianPfliegel `Remove sqlExtensionHelp (#312)`
|
||||
* olljanat for `Implemented npm version check (#314)`
|
||||
* Adam Mechanic for helping with the `whoisactive` extension
|
||||
* All community localization contributors *(will get list of individuals next month)*
|
||||
|
||||
And of course we'd like to thank the authors of all upstream dependencies. Please see a full list in the [ThirdPartyNotices.txt](https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/ThirdPartyNotices.txt)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ install:
|
||||
build_script:
|
||||
- yarn
|
||||
- .\node_modules\.bin\gulp electron
|
||||
- .\node_modules\.bin\tsc -p .\src\tsconfig.monaco.json --noEmit
|
||||
- npm run compile
|
||||
|
||||
test_script:
|
||||
|
||||
12
build/builtInExtensions.json
Normal file
12
build/builtInExtensions.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "ms-vscode.node-debug",
|
||||
"version": "1.21.8",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug"
|
||||
},
|
||||
{
|
||||
"name": "ms-vscode.node-debug2",
|
||||
"version": "1.21.2",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug2"
|
||||
}
|
||||
]
|
||||
20
build/builtin/.eslintrc
Normal file
20
build/builtin/.eslintrc
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"browser": true
|
||||
},
|
||||
"rules": {
|
||||
"no-console": 0,
|
||||
"no-cond-assign": 0,
|
||||
"no-unused-vars": 1,
|
||||
"no-extra-semi": "warn",
|
||||
"semi": "warn"
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
}
|
||||
}
|
||||
126
build/builtin/browser-main.js
Normal file
126
build/builtin/browser-main.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
// @ts-ignore review
|
||||
const { remote } = require('electron');
|
||||
const dialog = remote.dialog;
|
||||
|
||||
const builtInExtensionsPath = path.join(__dirname, '..', 'builtInExtensions.json');
|
||||
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
|
||||
function readJson(filePath) {
|
||||
return JSON.parse(fs.readFileSync(filePath, { encoding: 'utf8' }));
|
||||
}
|
||||
|
||||
function writeJson(filePath, obj) {
|
||||
fs.writeFileSync(filePath, JSON.stringify(obj, null, 2));
|
||||
}
|
||||
|
||||
function renderOption(form, id, title, value, checked) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'radio';
|
||||
input.id = id;
|
||||
input.name = 'choice';
|
||||
input.value = value;
|
||||
input.checked = !!checked;
|
||||
form.appendChild(input);
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.setAttribute('for', id);
|
||||
label.textContent = title;
|
||||
form.appendChild(label);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
function render(el, state) {
|
||||
function setState(state) {
|
||||
try {
|
||||
writeJson(controlFilePath, state.control);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
el.innerHTML = '';
|
||||
render(el, state);
|
||||
}
|
||||
|
||||
const ul = document.createElement('ul');
|
||||
const { builtin, control } = state;
|
||||
|
||||
for (const ext of builtin) {
|
||||
const controlState = control[ext.name] || 'marketplace';
|
||||
|
||||
const li = document.createElement('li');
|
||||
ul.appendChild(li);
|
||||
|
||||
const name = document.createElement('code');
|
||||
name.textContent = ext.name;
|
||||
li.appendChild(name);
|
||||
|
||||
const form = document.createElement('form');
|
||||
li.appendChild(form);
|
||||
|
||||
const marketplaceInput = renderOption(form, `marketplace-${ext.name}`, 'Marketplace', 'marketplace', controlState === 'marketplace');
|
||||
marketplaceInput.onchange = function () {
|
||||
control[ext.name] = 'marketplace';
|
||||
setState({ builtin, control });
|
||||
};
|
||||
|
||||
const disabledInput = renderOption(form, `disabled-${ext.name}`, 'Disabled', 'disabled', controlState === 'disabled');
|
||||
disabledInput.onchange = function () {
|
||||
control[ext.name] = 'disabled';
|
||||
setState({ builtin, control });
|
||||
};
|
||||
|
||||
let local = undefined;
|
||||
|
||||
if (controlState !== 'marketplace' && controlState !== 'disabled') {
|
||||
local = controlState;
|
||||
}
|
||||
|
||||
const localInput = renderOption(form, `local-${ext.name}`, 'Local', 'local', !!local);
|
||||
localInput.onchange = function () {
|
||||
const result = dialog.showOpenDialog(remote.getCurrentWindow(), {
|
||||
title: 'Choose Folder',
|
||||
properties: ['openDirectory']
|
||||
});
|
||||
|
||||
if (result && result.length >= 1) {
|
||||
control[ext.name] = result[0];
|
||||
}
|
||||
|
||||
setState({ builtin, control });
|
||||
};
|
||||
|
||||
if (local) {
|
||||
const localSpan = document.createElement('code');
|
||||
localSpan.className = 'local';
|
||||
localSpan.textContent = local;
|
||||
form.appendChild(localSpan);
|
||||
}
|
||||
}
|
||||
|
||||
el.appendChild(ul);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const el = document.getElementById('extensions');
|
||||
const builtin = readJson(builtInExtensionsPath);
|
||||
let control;
|
||||
|
||||
try {
|
||||
control = readJson(controlFilePath);
|
||||
} catch (err) {
|
||||
control = {};
|
||||
}
|
||||
|
||||
render(el, { builtin, control });
|
||||
}
|
||||
|
||||
window.onload = main;
|
||||
46
build/builtin/index.html
Normal file
46
build/builtin/index.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Manage Built-in Extensions</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="browser-main.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: 'Menlo', 'Courier New', 'Courier', monospace;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
padding: 0.3em 0;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 0.3em 0 0.3em 0.3em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Built-in Extensions</h1>
|
||||
<div id="extensions"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
20
build/builtin/main.js
Normal file
20
build/builtin/main.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const { app, BrowserWindow } = require('electron');
|
||||
const url = require('url');
|
||||
const path = require('path');
|
||||
|
||||
let window = null;
|
||||
|
||||
app.once('ready', () => {
|
||||
window = new BrowserWindow({ width: 800, height: 600 });
|
||||
window.setMenuBarVisibility(false);
|
||||
window.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true }));
|
||||
// window.webContents.openDevTools();
|
||||
window.once('closed', () => window = null);
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => app.quit());
|
||||
5
build/builtin/package.json
Normal file
5
build/builtin/package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "builtin",
|
||||
"version": "0.1.0",
|
||||
"main": "main.js"
|
||||
}
|
||||
@@ -12,6 +12,7 @@ var File = require('vinyl');
|
||||
|
||||
var root = path.dirname(__dirname);
|
||||
var sha1 = util.getVersion(root);
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
var semver = require('./monaco/package.json').version;
|
||||
var headerVersion = semver + '(' + sha1 + ')';
|
||||
|
||||
@@ -21,14 +22,14 @@ var editorEntryPoints = [
|
||||
{
|
||||
name: 'vs/editor/editor.main',
|
||||
include: [],
|
||||
exclude: [ 'vs/css', 'vs/nls' ],
|
||||
prepend: [ 'out-build/vs/css.js', 'out-build/vs/nls.js' ],
|
||||
exclude: ['vs/css', 'vs/nls'],
|
||||
prepend: ['out-build/vs/css.js', 'out-build/vs/nls.js'],
|
||||
},
|
||||
{
|
||||
name: 'vs/base/common/worker/simpleWorker',
|
||||
include: [ 'vs/editor/common/services/editorSimpleWorker' ],
|
||||
prepend: [ 'vs/loader.js' ],
|
||||
append: [ 'vs/base/worker/workerMain' ],
|
||||
include: ['vs/editor/common/services/editorSimpleWorker'],
|
||||
prepend: ['vs/loader.js'],
|
||||
append: ['vs/base/worker/workerMain'],
|
||||
dest: 'vs/base/worker/workerMain.js'
|
||||
}
|
||||
];
|
||||
@@ -79,14 +80,15 @@ gulp.task('optimize-editor', ['clean-optimized-editor', 'compile-client-build'],
|
||||
bundleLoader: false,
|
||||
header: BUNDLED_FILE_HEADER,
|
||||
bundleInfo: true,
|
||||
out: 'out-editor'
|
||||
out: 'out-editor',
|
||||
languages: undefined
|
||||
}));
|
||||
|
||||
gulp.task('clean-minified-editor', util.rimraf('out-editor-min'));
|
||||
gulp.task('minify-editor', ['clean-minified-editor', 'optimize-editor'], common.minifyTask('out-editor'));
|
||||
|
||||
gulp.task('clean-editor-distro', util.rimraf('out-monaco-editor-core'));
|
||||
gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-editor'], function() {
|
||||
gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-editor'], function () {
|
||||
return es.merge(
|
||||
// other assets
|
||||
es.merge(
|
||||
@@ -97,17 +99,17 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
|
||||
|
||||
// package.json
|
||||
gulp.src('build/monaco/package.json')
|
||||
.pipe(es.through(function(data) {
|
||||
.pipe(es.through(function (data) {
|
||||
var json = JSON.parse(data.contents.toString());
|
||||
json.private = false;
|
||||
data.contents = new Buffer(JSON.stringify(json, null, ' '));
|
||||
data.contents = Buffer.from(JSON.stringify(json, null, ' '));
|
||||
this.emit('data', data);
|
||||
}))
|
||||
.pipe(gulp.dest('out-monaco-editor-core')),
|
||||
|
||||
// README.md
|
||||
gulp.src('build/monaco/README-npm.md')
|
||||
.pipe(es.through(function(data) {
|
||||
.pipe(es.through(function (data) {
|
||||
this.emit('data', new File({
|
||||
path: data.path.replace(/README-npm\.md/, 'README.md'),
|
||||
base: data.base,
|
||||
@@ -124,10 +126,10 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
|
||||
// min folder
|
||||
es.merge(
|
||||
gulp.src('out-editor-min/**/*')
|
||||
).pipe(filterStream(function(path) {
|
||||
).pipe(filterStream(function (path) {
|
||||
// no map files
|
||||
return !/(\.js\.map$)|(nls\.metadata\.json$)|(bundleInfo\.json$)/.test(path);
|
||||
})).pipe(es.through(function(data) {
|
||||
})).pipe(es.through(function (data) {
|
||||
// tweak the sourceMappingURL
|
||||
if (!/\.js$/.test(data.path)) {
|
||||
this.emit('data', data);
|
||||
@@ -140,49 +142,50 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
|
||||
var newStr = '//# sourceMappingURL=' + relativePathToMap.replace(/\\/g, '/');
|
||||
strContents = strContents.replace(/\/\/\# sourceMappingURL=[^ ]+$/, newStr);
|
||||
|
||||
data.contents = new Buffer(strContents);
|
||||
data.contents = Buffer.from(strContents);
|
||||
this.emit('data', data);
|
||||
})).pipe(gulp.dest('out-monaco-editor-core/min')),
|
||||
|
||||
// min-maps folder
|
||||
es.merge(
|
||||
gulp.src('out-editor-min/**/*')
|
||||
).pipe(filterStream(function(path) {
|
||||
).pipe(filterStream(function (path) {
|
||||
// no map files
|
||||
return /\.js\.map$/.test(path);
|
||||
})).pipe(gulp.dest('out-monaco-editor-core/min-maps'))
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task('analyze-editor-distro', function() {
|
||||
gulp.task('analyze-editor-distro', function () {
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
var bundleInfo = require('../out-editor/bundleInfo.json');
|
||||
var graph = bundleInfo.graph;
|
||||
var bundles = bundleInfo.bundles;
|
||||
|
||||
var inverseGraph = {};
|
||||
Object.keys(graph).forEach(function(module) {
|
||||
Object.keys(graph).forEach(function (module) {
|
||||
var dependencies = graph[module];
|
||||
dependencies.forEach(function(dep) {
|
||||
dependencies.forEach(function (dep) {
|
||||
inverseGraph[dep] = inverseGraph[dep] || [];
|
||||
inverseGraph[dep].push(module);
|
||||
});
|
||||
});
|
||||
|
||||
var detailed = {};
|
||||
Object.keys(bundles).forEach(function(entryPoint) {
|
||||
Object.keys(bundles).forEach(function (entryPoint) {
|
||||
var included = bundles[entryPoint];
|
||||
var includedMap = {};
|
||||
included.forEach(function(included) {
|
||||
included.forEach(function (included) {
|
||||
includedMap[included] = true;
|
||||
});
|
||||
|
||||
var explanation = [];
|
||||
included.map(function(included) {
|
||||
included.map(function (included) {
|
||||
if (included.indexOf('!') >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var reason = (inverseGraph[included]||[]).filter(function(mod) {
|
||||
var reason = (inverseGraph[included] || []).filter(function (mod) {
|
||||
return !!includedMap[mod];
|
||||
});
|
||||
explanation.push({
|
||||
@@ -198,7 +201,7 @@ gulp.task('analyze-editor-distro', function() {
|
||||
});
|
||||
|
||||
function filterStream(testFunc) {
|
||||
return es.through(function(data) {
|
||||
return es.through(function (data) {
|
||||
if (!testFunc(data.relative)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ const sourcemaps = require('gulp-sourcemaps');
|
||||
const nlsDev = require('vscode-nls-dev');
|
||||
const root = path.dirname(__dirname);
|
||||
const commit = util.getVersion(root);
|
||||
const i18n = require('./lib/i18n');
|
||||
|
||||
const extensionsPath = path.join(path.dirname(__dirname), 'extensions');
|
||||
|
||||
@@ -29,7 +30,8 @@ const compilations = glob.sync('**/tsconfig.json', {
|
||||
});
|
||||
|
||||
const getBaseUrl = out => `https://ticino.blob.core.windows.net/sourcemaps/${commit}/${out}`;
|
||||
const languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita'];
|
||||
|
||||
const languages = i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []);
|
||||
|
||||
const tasks = compilations.map(function (tsconfigFile) {
|
||||
const absolutePath = path.join(extensionsPath, tsconfigFile);
|
||||
@@ -55,9 +57,19 @@ const tasks = compilations.map(function (tsconfigFile) {
|
||||
const srcBase = path.join(root, 'src');
|
||||
const src = path.join(srcBase, '**');
|
||||
const out = path.join(root, 'out');
|
||||
const i18n = path.join(__dirname, '..', 'i18n');
|
||||
const i18nPath = path.join(__dirname, '..', 'i18n');
|
||||
const baseUrl = getBaseUrl(out);
|
||||
|
||||
let headerId, headerOut;
|
||||
let index = relativeDirname.indexOf('/');
|
||||
if (index < 0) {
|
||||
headerId = 'vscode.' + relativeDirname;
|
||||
headerOut = 'out';
|
||||
} else {
|
||||
headerId = 'vscode.' + relativeDirname.substr(0, index);
|
||||
headerOut = relativeDirname.substr(index + 1) + '/out';
|
||||
}
|
||||
|
||||
function createPipeline(build, emitError) {
|
||||
const reporter = createReporter();
|
||||
|
||||
@@ -82,7 +94,9 @@ const tasks = compilations.map(function (tsconfigFile) {
|
||||
sourceRoot: '../src'
|
||||
}))
|
||||
.pipe(tsFilter.restore)
|
||||
.pipe(build ? nlsDev.createAdditionalLanguageFiles(languages, i18n, out) : es.through())
|
||||
.pipe(build ? nlsDev.createAdditionalLanguageFiles(languages, i18nPath, out) : es.through())
|
||||
.pipe(build ? nlsDev.bundleMetaDataFiles(headerId, headerOut) : es.through())
|
||||
.pipe(build ? nlsDev.bundleLanguageFiles() : es.through())
|
||||
.pipe(reporter.end(emitError));
|
||||
|
||||
return es.duplex(input, output);
|
||||
@@ -129,7 +143,7 @@ const tasks = compilations.map(function (tsconfigFile) {
|
||||
const watchInput = watcher(src, srcOpts);
|
||||
|
||||
return watchInput
|
||||
.pipe(util.incremental(() => pipeline(true), input))
|
||||
.pipe(util.incremental(() => pipeline(), input))
|
||||
.pipe(gulp.dest(out));
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,11 @@ const gulptslint = require('gulp-tslint');
|
||||
const gulpeslint = require('gulp-eslint');
|
||||
const tsfmt = require('typescript-formatter');
|
||||
const tslint = require('tslint');
|
||||
const VinylFile = require('vinyl');
|
||||
const vfs = require('vinyl-fs');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const pall = require('p-all');
|
||||
|
||||
/**
|
||||
* Hygiene works by creating cascading subsets of all our files and
|
||||
@@ -29,55 +33,56 @@ const all = [
|
||||
'extensions/**/*',
|
||||
'scripts/**/*',
|
||||
'src/**/*',
|
||||
'test/**/*'
|
||||
];
|
||||
|
||||
const eolFilter = [
|
||||
'**',
|
||||
'!ThirdPartyNotices.txt',
|
||||
'!LICENSE.txt',
|
||||
'!extensions/**/out/**',
|
||||
'!test/smoke/out/**',
|
||||
'!**/node_modules/**',
|
||||
'!**/fixtures/**',
|
||||
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot}',
|
||||
'!build/{lib,tslintRules}/**/*.js',
|
||||
'!build/monaco/**',
|
||||
'!build/win32/**',
|
||||
'!build/**/*.sh',
|
||||
'!build/tfs/**/*.js',
|
||||
'!**/Dockerfile'
|
||||
'test/**/*',
|
||||
'!**/node_modules/**'
|
||||
];
|
||||
|
||||
const indentationFilter = [
|
||||
'**',
|
||||
|
||||
// except specific files
|
||||
'!ThirdPartyNotices.txt',
|
||||
'!**/*.md',
|
||||
'!**/*.ps1',
|
||||
'!**/*.template',
|
||||
'!**/*.yaml',
|
||||
'!**/*.yml',
|
||||
'!**/yarn.lock',
|
||||
'!**/lib/**',
|
||||
'!extensions/**/*.d.ts',
|
||||
'!src/typings/**/*.d.ts',
|
||||
'!src/vs/*/**/*.d.ts',
|
||||
'!**/*.d.ts.recipe',
|
||||
'!LICENSE.txt',
|
||||
'!src/vs/nls.js',
|
||||
'!src/vs/css.js',
|
||||
'!src/vs/loader.js',
|
||||
'!src/vs/base/common/marked/raw.marked.js',
|
||||
'!src/vs/base/common/winjs.base.raw.js',
|
||||
'!src/vs/base/node/terminateProcess.sh',
|
||||
'!src/vs/base/node/ps-win.ps1',
|
||||
'!test/assert.js',
|
||||
|
||||
// except specific folders
|
||||
'!test/smoke/out/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace2/**',
|
||||
'!build/monaco/**',
|
||||
'!build/win32/**',
|
||||
|
||||
// except multiple specific files
|
||||
'!**/package.json',
|
||||
'!**/yarn.lock',
|
||||
|
||||
// except multiple specific folders
|
||||
'!**/octicons/**',
|
||||
'!**/vs/base/common/marked/raw.marked.js',
|
||||
'!**/vs/base/common/winjs.base.raw.js',
|
||||
'!**/vs/base/node/terminateProcess.sh',
|
||||
'!**/vs/base/node/ps-win.ps1',
|
||||
'!**/vs/nls.js',
|
||||
'!**/vs/css.js',
|
||||
'!**/vs/loader.js',
|
||||
'!**/fixtures/**',
|
||||
'!**/lib/**',
|
||||
'!extensions/**/out/**',
|
||||
'!extensions/**/snippets/**',
|
||||
'!extensions/**/syntaxes/**',
|
||||
'!extensions/**/themes/**',
|
||||
'!extensions/**/colorize-fixtures/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace/**'
|
||||
|
||||
// except specific file types
|
||||
'!src/vs/*/**/*.d.ts',
|
||||
'!src/typings/**/*.d.ts',
|
||||
'!extensions/**/*.d.ts',
|
||||
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe}',
|
||||
'!build/{lib,tslintRules}/**/*.js',
|
||||
'!build/**/*.sh',
|
||||
'!build/tfs/**/*.js',
|
||||
'!**/Dockerfile',
|
||||
'!extensions/markdown/media/*.js'
|
||||
];
|
||||
|
||||
const copyrightFilter = [
|
||||
@@ -95,6 +100,7 @@ const copyrightFilter = [
|
||||
'!**/*.xpm',
|
||||
'!**/*.opts',
|
||||
'!**/*.disabled',
|
||||
'!**/*.code-workspace',
|
||||
'!build/**/*.init',
|
||||
'!resources/linux/snap/snapcraft.yaml',
|
||||
'!resources/win32/bin/code.js',
|
||||
@@ -124,6 +130,7 @@ const tslintFilter = [
|
||||
'!**/node_modules/**',
|
||||
'!extensions/typescript/test/colorize-fixtures/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace2/**',
|
||||
'!extensions/**/*.test.ts',
|
||||
'!extensions/html/server/lib/jquery.d.ts'
|
||||
];
|
||||
@@ -144,31 +151,23 @@ gulp.task('eslint', () => {
|
||||
});
|
||||
|
||||
gulp.task('tslint', () => {
|
||||
// {{SQL CARBON EDIT}}
|
||||
const options = { emitError: false };
|
||||
|
||||
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
|
||||
.pipe(filter(tslintFilter))
|
||||
.pipe(gulptslint({ rulesDirectory: 'build/lib/tslint' }))
|
||||
.pipe(gulptslint.report(options));
|
||||
.pipe(gulptslint.default({ rulesDirectory: 'build/lib/tslint' }))
|
||||
.pipe(gulptslint.default.report(options));
|
||||
});
|
||||
|
||||
const hygiene = exports.hygiene = (some, options) => {
|
||||
options = options || {};
|
||||
function hygiene(some) {
|
||||
let errorCount = 0;
|
||||
|
||||
const eol = es.through(function (file) {
|
||||
if (/\r\n?/g.test(file.contents.toString('utf8'))) {
|
||||
console.error(file.relative + ': Bad EOL found');
|
||||
errorCount++;
|
||||
}
|
||||
|
||||
this.emit('data', file);
|
||||
});
|
||||
|
||||
const indentation = es.through(function (file) {
|
||||
file.contents
|
||||
.toString('utf8')
|
||||
.split(/\r\n|\r|\n/)
|
||||
const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
|
||||
file.__lines = lines;
|
||||
|
||||
lines
|
||||
.forEach((line, i) => {
|
||||
if (/^\s*$/.test(line)) {
|
||||
// empty or whitespace lines are OK
|
||||
@@ -186,9 +185,14 @@ const hygiene = exports.hygiene = (some, options) => {
|
||||
});
|
||||
|
||||
const copyrights = es.through(function (file) {
|
||||
if (file.contents.toString('utf8').indexOf(copyrightHeader) !== 0) {
|
||||
console.error(file.relative + ': Missing or bad copyright statement');
|
||||
errorCount++;
|
||||
const lines = file.__lines;
|
||||
|
||||
for (let i = 0; i < copyrightHeaderLines.length; i++) {
|
||||
if (lines[i] !== copyrightHeaderLines[i]) {
|
||||
console.error(file.relative + ': Missing or bad copyright statement');
|
||||
errorCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('data', file);
|
||||
@@ -196,12 +200,20 @@ const hygiene = exports.hygiene = (some, options) => {
|
||||
|
||||
const formatting = es.map(function (file, cb) {
|
||||
tsfmt.processString(file.path, file.contents.toString('utf8'), {
|
||||
verify: true,
|
||||
verify: false,
|
||||
tsfmt: true,
|
||||
// verbose: true
|
||||
// keep checkJS happy
|
||||
editorconfig: undefined,
|
||||
replace: undefined,
|
||||
tsconfig: undefined,
|
||||
tslint: undefined
|
||||
}).then(result => {
|
||||
if (result.error) {
|
||||
console.error(result.message);
|
||||
let original = result.src.replace(/\r\n/gm, '\n');
|
||||
let formatted = result.dest.replace(/\r\n/gm, '\n');
|
||||
|
||||
if (original !== formatted) {
|
||||
console.error('File not formatted:', file.relative);
|
||||
errorCount++;
|
||||
}
|
||||
cb(null, file);
|
||||
@@ -211,43 +223,31 @@ const hygiene = exports.hygiene = (some, options) => {
|
||||
});
|
||||
});
|
||||
|
||||
function reportFailures(failures) {
|
||||
failures.forEach(failure => {
|
||||
const name = failure.name || failure.fileName;
|
||||
const position = failure.startPosition;
|
||||
const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line;
|
||||
const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character;
|
||||
|
||||
// console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`);
|
||||
});
|
||||
}
|
||||
const tslintConfiguration = tslint.Configuration.findConfiguration('tslint.json', '.');
|
||||
const tslintOptions = { fix: false, formatter: 'json' };
|
||||
const tsLinter = new tslint.Linter(tslintOptions);
|
||||
|
||||
const tsl = es.through(function (file) {
|
||||
const configuration = tslint.Configuration.findConfiguration(null, '.');
|
||||
const options = { formatter: 'json', rulesDirectory: 'build/lib/tslint' };
|
||||
const contents = file.contents.toString('utf8');
|
||||
const linter = new tslint.Linter(options);
|
||||
linter.lint(file.relative, contents, configuration.results);
|
||||
const result = linter.getResult();
|
||||
|
||||
if (result.failures.length > 0) {
|
||||
reportFailures(result.failures);
|
||||
errorCount += result.failures.length;
|
||||
}
|
||||
|
||||
tsLinter.lint(file.relative, contents, tslintConfiguration.results);
|
||||
this.emit('data', file);
|
||||
});
|
||||
|
||||
const result = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true })
|
||||
let input;
|
||||
|
||||
if (Array.isArray(some) || typeof some === 'string' || !some) {
|
||||
input = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true });
|
||||
} else {
|
||||
input = some;
|
||||
}
|
||||
|
||||
const result = input
|
||||
.pipe(filter(f => !f.stat.isDirectory()))
|
||||
.pipe(filter(eolFilter))
|
||||
// {{SQL CARBON EDIT}}
|
||||
//.pipe(options.skipEOL ? es.through() : eol)
|
||||
.pipe(filter(indentationFilter))
|
||||
.pipe(indentation)
|
||||
.pipe(filter(copyrightFilter))
|
||||
.pipe(filter(copyrightFilter));
|
||||
// {{SQL CARBON EDIT}}
|
||||
//.pipe(copyrights);
|
||||
// .pipe(copyrights);
|
||||
|
||||
const typescript = result
|
||||
.pipe(filter(tslintFilter))
|
||||
@@ -257,23 +257,52 @@ const hygiene = exports.hygiene = (some, options) => {
|
||||
const javascript = result
|
||||
.pipe(filter(eslintFilter))
|
||||
.pipe(gulpeslint('src/.eslintrc'))
|
||||
.pipe(gulpeslint.formatEach('compact'))
|
||||
// {{SQL CARBON EDIT}}
|
||||
.pipe(gulpeslint.formatEach('compact'));
|
||||
// {{SQL CARBON EDIT}}
|
||||
// .pipe(gulpeslint.failAfterError());
|
||||
|
||||
return es.merge(typescript, javascript)
|
||||
.pipe(es.through(null, function () {
|
||||
// {{SQL CARBON EDIT}}
|
||||
// if (errorCount > 0) {
|
||||
// this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
|
||||
// } else {
|
||||
// this.emit('end');
|
||||
// }
|
||||
this.emit('end');
|
||||
}));
|
||||
};
|
||||
let count = 0;
|
||||
return es.merge(typescript, javascript)
|
||||
.pipe(es.through(function (data) {
|
||||
// {{SQL CARBON EDIT}}
|
||||
this.emit('end');
|
||||
}));
|
||||
}
|
||||
|
||||
gulp.task('hygiene', () => hygiene(''));
|
||||
function createGitIndexVinyls(paths) {
|
||||
const cp = require('child_process');
|
||||
const repositoryPath = process.cwd();
|
||||
|
||||
const fns = paths.map(relativePath => () => new Promise((c, e) => {
|
||||
const fullPath = path.join(repositoryPath, relativePath);
|
||||
|
||||
fs.stat(fullPath, (err, stat) => {
|
||||
if (err && err.code === 'ENOENT') { // ignore deletions
|
||||
return c(null);
|
||||
} else if (err) {
|
||||
return e(err);
|
||||
}
|
||||
|
||||
cp.exec(`git show :${relativePath}`, { maxBuffer: 2000 * 1024, encoding: 'buffer' }, (err, out) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
|
||||
c(new VinylFile({
|
||||
path: fullPath,
|
||||
base: repositoryPath,
|
||||
contents: out,
|
||||
stat
|
||||
}));
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
return pall(fns, { concurrency: 4 })
|
||||
.then(r => r.filter(p => !!p));
|
||||
}
|
||||
|
||||
gulp.task('hygiene', () => hygiene());
|
||||
|
||||
// this allows us to run hygiene as a git pre-commit hook
|
||||
if (require.main === module) {
|
||||
@@ -284,22 +313,19 @@ if (require.main === module) {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
cp.exec('git config core.autocrlf', (err, out) => {
|
||||
const skipEOL = out.trim() === 'true';
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
return hygiene(process.argv.slice(2), { skipEOL: skipEOL }).on('error', err => {
|
||||
console.error();
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
hygiene(process.argv.slice(2)).on('error', err => {
|
||||
console.error();
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
cp.exec('git diff --cached --name-only', { maxBuffer: 2000 * 1024 }, (err, out) => {
|
||||
if (err) {
|
||||
console.error();
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
const some = out
|
||||
@@ -307,12 +333,18 @@ if (require.main === module) {
|
||||
.filter(l => !!l);
|
||||
|
||||
if (some.length > 0) {
|
||||
hygiene(some, { skipEOL: skipEOL }).on('error', err => {
|
||||
console.error();
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
console.log('Reading git index versions...');
|
||||
|
||||
createGitIndexVinyls(some)
|
||||
.then(vinyls => new Promise((c, e) => hygiene(es.readArray(vinyls))
|
||||
.on('end', () => c())
|
||||
.on('error', e)))
|
||||
.catch(err => {
|
||||
console.error();
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,21 @@
|
||||
'use strict';
|
||||
|
||||
const gulp = require('gulp');
|
||||
const json = require('gulp-json-editor');
|
||||
const buffer = require('gulp-buffer');
|
||||
const filter = require('gulp-filter');
|
||||
const es = require('event-stream');
|
||||
const util = require('./lib/util');
|
||||
const remote = require('gulp-remote-src');
|
||||
const zip = require('gulp-vinyl-zip');
|
||||
const assign = require('object-assign');
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
const jeditor = require('gulp-json-editor');
|
||||
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const pkg = require('../package.json');
|
||||
|
||||
gulp.task('mixin', function () {
|
||||
// {{SQL CARBON EDIT}}
|
||||
const updateUrl = process.env['SQLOPS_UPDATEURL'];
|
||||
|
||||
@@ -13,14 +13,6 @@ const filter = require('gulp-filter');
|
||||
|
||||
gulp.task('clean-mssql-extension', util.rimraf('extensions/mssql/node_modules'));
|
||||
gulp.task('clean-credentials-extension', util.rimraf('extensions/credentials/node_modules'));
|
||||
gulp.task('clean-extensions-modules', util.rimraf('extensions-modules/node_modules'));
|
||||
gulp.task('clean-protocol', ['clean-extensions-modules', 'clean-mssql-extension', 'clean-credentials-extension', 'clean-client', 'clean-jsonrpc', 'clean-server', 'clean-types']);
|
||||
|
||||
// Tasks to clean extensions modules
|
||||
gulp.task('clean-mssql-ext-mod', util.rimraf('extensions/mssql/node_modules/extensions-modules'));
|
||||
gulp.task('clean-credentials-ext-mod', util.rimraf('extensions/credentials/node_modules/extensions-modules'));
|
||||
gulp.task('clean-build-ext-mod', util.rimraf('build/node_modules/extensions-modules'));
|
||||
gulp.task('clean-ext-mod', ['clean-mssql-ext-mod', 'clean-credentials-ext-mod', 'clean-build-ext-mod', 'clean-extensions-modules']);
|
||||
|
||||
gulp.task('fmt', () => formatStagedFiles());
|
||||
const formatFiles = (some) => {
|
||||
|
||||
@@ -27,17 +27,22 @@ const common = require('./lib/optimize');
|
||||
const nlsDev = require('vscode-nls-dev');
|
||||
const root = path.dirname(__dirname);
|
||||
const commit = util.getVersion(root);
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const packageJson = require('../package.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const product = require('../product.json');
|
||||
const crypto = require('crypto');
|
||||
const i18n = require('./lib/i18n');
|
||||
const serviceInstaller = require('../extensions-modules/lib/languageservice/serviceInstallerUtil');
|
||||
// {{SQL CARBON EDIT}}
|
||||
const serviceDownloader = require('service-downloader').ServiceDownloadProvider;
|
||||
const platformInfo = require('service-downloader/out/platform').PlatformInformation;
|
||||
const glob = require('glob');
|
||||
const deps = require('./dependencies');
|
||||
const getElectronVersion = require('./lib/electron').getElectronVersion;
|
||||
const createAsar = require('./lib/asar').createAsar;
|
||||
|
||||
const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
|
||||
|
||||
// @ts-ignore
|
||||
// {{SQL CARBON EDIT}}
|
||||
var del = require('del');
|
||||
const extensionsRoot = path.join(root, 'extensions');
|
||||
@@ -55,16 +60,16 @@ const nodeModules = [
|
||||
.concat(_.uniq(productionDependencies.map(d => d.name)))
|
||||
.concat(baseModules);
|
||||
|
||||
// Build
|
||||
|
||||
const builtInExtensions = [
|
||||
{ name: 'ms-vscode.node-debug', version: '1.19.8' },
|
||||
{ name: 'ms-vscode.node-debug2', version: '1.19.4' }
|
||||
];
|
||||
// Build
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const builtInExtensions = require('./builtInExtensions.json');
|
||||
|
||||
const excludedExtensions = [
|
||||
'vscode-api-tests',
|
||||
'vscode-colorize-tests'
|
||||
'vscode-colorize-tests',
|
||||
'ms-vscode.node-debug',
|
||||
'ms-vscode.node-debug2',
|
||||
];
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -103,7 +108,8 @@ const vscodeResources = [
|
||||
'out-build/vs/workbench/parts/welcome/walkThrough/**/*.md',
|
||||
'out-build/vs/workbench/services/files/**/*.exe',
|
||||
'out-build/vs/workbench/services/files/**/*.md',
|
||||
'out-build/vs/code/electron-browser/sharedProcess.js',
|
||||
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
||||
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
||||
// {{SQL CARBON EDIT}}
|
||||
'out-build/sql/workbench/electron-browser/splashscreen/*',
|
||||
'out-build/sql/**/*.{svg,png,cur,html}',
|
||||
@@ -133,10 +139,7 @@ const BUNDLED_FILE_HEADER = [
|
||||
' *--------------------------------------------------------*/'
|
||||
].join('\n');
|
||||
|
||||
var languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita'];
|
||||
if (process.env.VSCODE_QUALITY !== 'stable') {
|
||||
languages = languages.concat(['ptb', 'hun', 'trk']); // Add languages requested by the community to non-stable builds
|
||||
}
|
||||
const languages = i18n.defaultLanguages.concat([]); // i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []);
|
||||
|
||||
gulp.task('clean-optimized-vscode', util.rimraf('out-vscode'));
|
||||
gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compile-extensions-build'], common.optimizeTask({
|
||||
@@ -146,7 +149,8 @@ gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compil
|
||||
loaderConfig: common.loaderConfig(nodeModules),
|
||||
header: BUNDLED_FILE_HEADER,
|
||||
out: 'out-vscode',
|
||||
languages: languages
|
||||
languages: languages,
|
||||
bundleInfo: undefined
|
||||
}));
|
||||
|
||||
|
||||
@@ -168,7 +172,7 @@ const config = {
|
||||
version: getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2017 Microsoft. All rights reserved',
|
||||
copyright: 'Copyright (C) 2018 Microsoft. All rights reserved',
|
||||
darwinIcon: 'resources/darwin/code.icns',
|
||||
darwinBundleIdentifier: product.darwinBundleIdentifier,
|
||||
darwinApplicationCategoryType: 'public.app-category.developer-tools',
|
||||
@@ -187,7 +191,7 @@ const config = {
|
||||
name: product.nameLong,
|
||||
urlSchemes: [product.urlProtocol]
|
||||
}],
|
||||
darwinCredits: darwinCreditsTemplate ? new Buffer(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : void 0,
|
||||
darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : void 0,
|
||||
linuxExecutableName: product.applicationName,
|
||||
winIcon: 'resources/win32/code.ico',
|
||||
token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || void 0,
|
||||
@@ -325,16 +329,12 @@ function packageTask(platform, arch, opts) {
|
||||
const localExtensionDependencies = gulp.src(extensionDepsSrc, { base: '.', dot: true })
|
||||
.pipe(filter(['**', '!**/package-lock.json']))
|
||||
.pipe(util.cleanNodeModule('account-provider-azure', ['node_modules/date-utils/doc/**', 'node_modules/adal_node/node_modules/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('dataprotocol-client', ['node_modules/**', 'src/*.js'], undefined))
|
||||
.pipe(util.cleanNodeModule('extensions-modules', ['node_modules/**', 'src/*.js'], undefined))
|
||||
.pipe(util.cleanNodeModule('typescript', ['**/**'], undefined));
|
||||
|
||||
|
||||
const sources = es.merge(src, localExtensions, localExtensionDependencies)
|
||||
.pipe(util.setExecutableBit(['**/*.sh']))
|
||||
.pipe(filter(['**',
|
||||
'!**/*.js.map',
|
||||
'!extensions/**/node_modules/**/{test, tests}/**',
|
||||
'!extensions/**/node_modules/**/test.js']));
|
||||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
|
||||
let version = packageJson.version;
|
||||
const quality = product.quality;
|
||||
@@ -358,7 +358,7 @@ function packageTask(platform, arch, opts) {
|
||||
|
||||
// TODO the API should be copied to `out` during compile, not here
|
||||
const api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts'));
|
||||
// {{SQL CARBON EDIT}}
|
||||
// {{SQL CARBON EDIT}}
|
||||
const dataApi = gulp.src('src/vs/data.d.ts').pipe(rename('out/sql/data.d.ts'));
|
||||
|
||||
const depsSrc = [
|
||||
@@ -372,6 +372,7 @@ function packageTask(platform, arch, opts) {
|
||||
.pipe(util.cleanNodeModule('oniguruma', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/*.js']))
|
||||
.pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('native-is-elevated', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('jschardet', ['dist/**']))
|
||||
@@ -379,18 +380,27 @@ function packageTask(platform, arch, opts) {
|
||||
.pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
|
||||
.pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js']))
|
||||
.pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node']))
|
||||
|
||||
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.exe', 'build/Release/*.dll', 'build/Release/*.node']))
|
||||
// {{SQL CARBON EDIT}}
|
||||
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.node', 'build/Release/*.dll', 'build/Release/*.exe']))
|
||||
.pipe(util.cleanNodeModule('chart.js', ['node_modules/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('emmet', ['node_modules/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('pty.js', ['build/**'], ['build/Release/**']))
|
||||
.pipe(util.cleanNodeModule('jquery-ui', ['external/**', 'demos/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('core-js', ['**/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('slickgrid', ['node_modules/**', 'examples/**'], undefined))
|
||||
|
||||
.pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a']))
|
||||
.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']));
|
||||
.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']))
|
||||
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
let copiedModules = gulp.src([
|
||||
'node_modules/jquery/**/*.*',
|
||||
'node_modules/reflect-metadata/**/*.*',
|
||||
'node_modules/slickgrid/**/*.*',
|
||||
'node_modules/underscore/**/*.*',
|
||||
'node_modules/zone.js/**/*.*',
|
||||
'node_modules/chart.js/**/*.*'
|
||||
], { base: '.', dot: true });
|
||||
|
||||
let all = es.merge(
|
||||
packageJsonStream,
|
||||
@@ -398,7 +408,8 @@ function packageTask(platform, arch, opts) {
|
||||
license,
|
||||
watermark,
|
||||
api,
|
||||
// {{SQL CARBON EDIT}}
|
||||
// {{SQL CARBON EDIT}}
|
||||
copiedModules,
|
||||
dataApi,
|
||||
sources,
|
||||
deps
|
||||
@@ -469,25 +480,21 @@ gulp.task('vscode-linux-x64-min', ['minify-vscode', 'clean-vscode-linux-x64'], p
|
||||
gulp.task('vscode-linux-arm-min', ['minify-vscode', 'clean-vscode-linux-arm'], packageTask('linux', 'arm', { minified: true }));
|
||||
|
||||
// Transifex Localizations
|
||||
const vscodeLanguages = [
|
||||
'zh-hans',
|
||||
'zh-hant',
|
||||
'ja',
|
||||
'ko',
|
||||
'de',
|
||||
'fr',
|
||||
'es',
|
||||
'ru',
|
||||
'it',
|
||||
'pt-br',
|
||||
'hu',
|
||||
'tr'
|
||||
];
|
||||
const setupDefaultLanguages = [
|
||||
'zh-hans',
|
||||
'zh-hant',
|
||||
'ko'
|
||||
];
|
||||
|
||||
const innoSetupConfig = {
|
||||
'zh-cn': { codePage: 'CP936', defaultInfo: { name: 'Simplified Chinese', id: '$0804', } },
|
||||
'zh-tw': { codePage: 'CP950', defaultInfo: { name: 'Traditional Chinese', id: '$0404' } },
|
||||
'ko': { codePage: 'CP949', defaultInfo: { name: 'Korean', id: '$0412' } },
|
||||
'ja': { codePage: 'CP932' },
|
||||
'de': { codePage: 'CP1252' },
|
||||
'fr': { codePage: 'CP1252' },
|
||||
'es': { codePage: 'CP1252' },
|
||||
'ru': { codePage: 'CP1251' },
|
||||
'it': { codePage: 'CP1252' },
|
||||
'pt-br': { codePage: 'CP1252' },
|
||||
'hu': { codePage: 'CP1250' },
|
||||
'tr': { codePage: 'CP1254' }
|
||||
};
|
||||
|
||||
const apiHostname = process.env.TRANSIFEX_API_URL;
|
||||
const apiName = process.env.TRANSIFEX_API_NAME;
|
||||
@@ -495,27 +502,48 @@ const apiToken = process.env.TRANSIFEX_API_TOKEN;
|
||||
|
||||
gulp.task('vscode-translations-push', ['optimize-vscode'], function () {
|
||||
const pathToMetadata = './out-vscode/nls.metadata.json';
|
||||
const pathToExtensions = './extensions/**/*.nls.json';
|
||||
const pathToExtensions = './extensions/*';
|
||||
const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}';
|
||||
|
||||
return es.merge(
|
||||
gulp.src(pathToMetadata).pipe(i18n.prepareXlfFiles()),
|
||||
gulp.src(pathToSetup).pipe(i18n.prepareXlfFiles()),
|
||||
gulp.src(pathToExtensions).pipe(i18n.prepareXlfFiles('vscode-extensions'))
|
||||
gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()),
|
||||
gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()),
|
||||
gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions())
|
||||
).pipe(i18n.findObsoleteResources(apiHostname, apiName, apiToken)
|
||||
).pipe(i18n.pushXlfFiles(apiHostname, apiName, apiToken));
|
||||
});
|
||||
|
||||
gulp.task('vscode-translations-pull', function () {
|
||||
gulp.task('vscode-translations-push-test', ['optimize-vscode'], function () {
|
||||
const pathToMetadata = './out-vscode/nls.metadata.json';
|
||||
const pathToExtensions = './extensions/*';
|
||||
const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}';
|
||||
|
||||
return es.merge(
|
||||
i18n.pullXlfFiles('vscode-editor', apiHostname, apiName, apiToken, vscodeLanguages),
|
||||
i18n.pullXlfFiles('vscode-workbench', apiHostname, apiName, apiToken, vscodeLanguages),
|
||||
i18n.pullXlfFiles('vscode-extensions', apiHostname, apiName, apiToken, vscodeLanguages),
|
||||
i18n.pullXlfFiles('vscode-setup', apiHostname, apiName, apiToken, setupDefaultLanguages)
|
||||
).pipe(vfs.dest('../vscode-localization'));
|
||||
gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()),
|
||||
gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()),
|
||||
gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions())
|
||||
).pipe(i18n.findObsoleteResources(apiHostname, apiName, apiToken)
|
||||
).pipe(vfs.dest('../vscode-transifex-input'));
|
||||
});
|
||||
|
||||
gulp.task('vscode-translations-pull', function () {
|
||||
[...i18n.defaultLanguages, ...i18n.extraLanguages].forEach(language => {
|
||||
i18n.pullCoreAndExtensionsXlfFiles(apiHostname, apiName, apiToken, language).pipe(vfs.dest(`../vscode-localization/${language.id}/build`));
|
||||
|
||||
let includeDefault = !!innoSetupConfig[language.id].defaultInfo;
|
||||
i18n.pullSetupXlfFiles(apiHostname, apiName, apiToken, language, includeDefault).pipe(vfs.dest(`../vscode-localization/${language.id}/setup`));
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('vscode-translations-import', function () {
|
||||
return gulp.src('../vscode-localization/**/*.xlf').pipe(i18n.prepareJsonFiles()).pipe(vfs.dest('./i18n'));
|
||||
[...i18n.defaultLanguages, ...i18n.extraLanguages].forEach(language => {
|
||||
gulp.src(`../vscode-localization/${language.id}/build/*/*.xlf`)
|
||||
.pipe(i18n.prepareI18nFiles())
|
||||
.pipe(vfs.dest(`./i18n/${language.folderName}`));
|
||||
gulp.src(`../vscode-localization/${language.id}/setup/*/*.xlf`)
|
||||
.pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id]))
|
||||
.pipe(vfs.dest(`./build/win32/i18n`));
|
||||
});
|
||||
});
|
||||
|
||||
// Sourcemaps
|
||||
@@ -541,7 +569,8 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => {
|
||||
const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
|
||||
gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => {
|
||||
const branch = process.env.BUILD_SOURCEBRANCH;
|
||||
if (!branch.endsWith('/master') && branch.indexOf('/release/') < 0) {
|
||||
|
||||
if (!/\/master$/.test(branch) && branch.indexOf('/release/') < 0) {
|
||||
console.log(`Only runs on master and release branches, not ${branch}`);
|
||||
return;
|
||||
}
|
||||
@@ -636,6 +665,7 @@ function versionStringToNumber(versionStr) {
|
||||
return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10);
|
||||
}
|
||||
|
||||
// This task is only run for the MacOS build
|
||||
gulp.task('generate-vscode-configuration', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buildDir = process.env['AGENT_BUILDDIRECTORY'];
|
||||
@@ -645,7 +675,8 @@ gulp.task('generate-vscode-configuration', () => {
|
||||
|
||||
const userDataDir = path.join(os.tmpdir(), 'tmpuserdata');
|
||||
const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
|
||||
const appPath = path.join(buildDir, 'VSCode-darwin/Visual\\ Studio\\ Code\\ -\\ Insiders.app/Contents/Resources/app/bin/code');
|
||||
const appName = process.env.VSCODE_QUALITY === 'insider' ? 'Visual\\ Studio\\ Code\\ -\\ Insiders.app' : 'Visual\\ Studio\\ Code.app';
|
||||
const appPath = path.join(buildDir, `VSCode-darwin/${appName}/Contents/Resources/app/bin/code`);
|
||||
const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`);
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
@@ -674,27 +705,25 @@ gulp.task('generate-vscode-configuration', () => {
|
||||
// {{SQL CARBON EDIT}}
|
||||
// Install service locally before building carbon
|
||||
|
||||
function installService(extObj, path) {
|
||||
var installer = new serviceInstaller.ServiceInstaller(extObj, path);
|
||||
installer.getServiceInstallDirectoryRoot().then(serviceInstallFolder => {
|
||||
console.log('Cleaning up the install folder: ' + serviceInstallFolder);
|
||||
del(serviceInstallFolder + '/*').then(() => {
|
||||
console.log('Installing the service. Install folder: ' + serviceInstallFolder);
|
||||
installer.installService();
|
||||
}, delError => {
|
||||
console.log('failed to delete the install folder error: ' + delError);
|
||||
});
|
||||
}, getFolderPathError => {
|
||||
console.log('failed to call getServiceInstallDirectoryRoot error: ' + getFolderPathError);
|
||||
function installService() {
|
||||
let config = require('../extensions/mssql/src/config.json');
|
||||
return platformInfo.getCurrent().then(p => {
|
||||
let runtime = p.runtimeId;
|
||||
// fix path since it won't be correct
|
||||
config.installDirectory = path.join(__dirname, '../extensions/mssql/src', config.installDirectory);
|
||||
var installer = new serviceDownloader(config);
|
||||
let serviceInstallFolder = installer.getInstallDirectory(runtime);
|
||||
console.log('Cleaning up the install folder: ' + serviceInstallFolder);
|
||||
return del(serviceInstallFolder + '/*').then(() => {
|
||||
console.log('Installing the service. Install folder: ' + serviceInstallFolder);
|
||||
return installer.installService(runtime);
|
||||
}, delError => {
|
||||
console.log('failed to delete the install folder error: ' + delError);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
gulp.task('install-sqltoolsservice', () => {
|
||||
var mssqlExt = require('../extensions/mssql/client/out/models/constants');
|
||||
var extObj = new mssqlExt.Constants();
|
||||
var path = '../extensions/mssql/client/out/config.json';
|
||||
return installService(extObj, path);
|
||||
return installService();
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -12,9 +12,12 @@ const shell = require('gulp-shell');
|
||||
const es = require('event-stream');
|
||||
const vfs = require('vinyl-fs');
|
||||
const util = require('./lib/util');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const packageJson = require('../package.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const product = require('../product.json');
|
||||
const rpmDependencies = require('../resources/linux/rpm/dependencies');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const rpmDependencies = require('../resources/linux/rpm/dependencies.json');
|
||||
|
||||
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
@@ -111,8 +114,7 @@ function buildDebPackage(arch) {
|
||||
return shell.task([
|
||||
'chmod 755 ' + product.applicationName + '-' + debArch + '/DEBIAN/postinst ' + product.applicationName + '-' + debArch + '/DEBIAN/prerm ' + product.applicationName + '-' + debArch + '/DEBIAN/postrm',
|
||||
'mkdir -p deb',
|
||||
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb',
|
||||
'dpkg-scanpackages deb /dev/null > Packages'
|
||||
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb'
|
||||
], { cwd: '.build/linux/deb/' + debArch });
|
||||
}
|
||||
|
||||
@@ -220,10 +222,10 @@ function prepareSnapPackage(arch) {
|
||||
|
||||
function buildSnapPackage(arch) {
|
||||
const snapBuildPath = getSnapBuildPath(arch);
|
||||
|
||||
const snapFilename = `${product.applicationName}-${packageJson.version}-${linuxPackageRevision}-${arch}.snap`;
|
||||
return shell.task([
|
||||
`chmod +x ${snapBuildPath}/electron-launch`,
|
||||
`cd ${snapBuildPath} && snapcraft snap`
|
||||
`cd ${snapBuildPath} && snapcraft snap --output ../${snapFilename}`
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,11 @@ const assert = require('assert');
|
||||
const cp = require('child_process');
|
||||
const _7z = require('7zip')['7z'];
|
||||
const util = require('./lib/util');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const pkg = require('../package.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const product = require('../product.json');
|
||||
const vfs = require('vinyl-fs');
|
||||
|
||||
const repoPath = path.dirname(__dirname);
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -91,3 +94,13 @@ gulp.task('vscode-win32-ia32-archive', ['clean-vscode-win32-ia32-archive'], arch
|
||||
|
||||
gulp.task('clean-vscode-win32-x64-archive', util.rimraf(zipDir('x64')));
|
||||
gulp.task('vscode-win32-x64-archive', ['clean-vscode-win32-x64-archive'], archiveWin32Setup('x64'));
|
||||
|
||||
function copyInnoUpdater(arch) {
|
||||
return () => {
|
||||
return gulp.src('build/win32/{inno_updater.exe,vcruntime140.dll}', { base: 'build/win32' })
|
||||
.pipe(vfs.dest(path.join(buildPath(arch), 'tools')));
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('vscode-win32-ia32-copy-inno-updater', copyInnoUpdater('ia32'));
|
||||
gulp.task('vscode-win32-x64-copy-inno-updater', copyInnoUpdater('x64'));
|
||||
118
build/lib/asar.js
Normal file
118
build/lib/asar.js
Normal file
@@ -0,0 +1,118 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 });
|
||||
var path = require("path");
|
||||
var es = require("event-stream");
|
||||
var pickle = require("chromium-pickle-js");
|
||||
var Filesystem = require("asar/lib/filesystem");
|
||||
var VinylFile = require("vinyl");
|
||||
var minimatch = require("minimatch");
|
||||
function createAsar(folderPath, unpackGlobs, destFilename) {
|
||||
var shouldUnpackFile = function (file) {
|
||||
for (var i = 0; i < unpackGlobs.length; i++) {
|
||||
if (minimatch(file.relative, unpackGlobs[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
var filesystem = new Filesystem(folderPath);
|
||||
var out = [];
|
||||
// Keep track of pending inserts
|
||||
var pendingInserts = 0;
|
||||
var onFileInserted = function () { pendingInserts--; };
|
||||
// Do not insert twice the same directory
|
||||
var seenDir = {};
|
||||
var insertDirectoryRecursive = function (dir) {
|
||||
if (seenDir[dir]) {
|
||||
return;
|
||||
}
|
||||
var lastSlash = dir.lastIndexOf('/');
|
||||
if (lastSlash === -1) {
|
||||
lastSlash = dir.lastIndexOf('\\');
|
||||
}
|
||||
if (lastSlash !== -1) {
|
||||
insertDirectoryRecursive(dir.substring(0, lastSlash));
|
||||
}
|
||||
seenDir[dir] = true;
|
||||
filesystem.insertDirectory(dir);
|
||||
};
|
||||
var insertDirectoryForFile = function (file) {
|
||||
var lastSlash = file.lastIndexOf('/');
|
||||
if (lastSlash === -1) {
|
||||
lastSlash = file.lastIndexOf('\\');
|
||||
}
|
||||
if (lastSlash !== -1) {
|
||||
insertDirectoryRecursive(file.substring(0, lastSlash));
|
||||
}
|
||||
};
|
||||
var insertFile = function (relativePath, stat, shouldUnpack) {
|
||||
insertDirectoryForFile(relativePath);
|
||||
pendingInserts++;
|
||||
filesystem.insertFile(relativePath, shouldUnpack, { stat: stat }, {}, onFileInserted);
|
||||
};
|
||||
return es.through(function (file) {
|
||||
if (file.stat.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
if (!file.stat.isFile()) {
|
||||
throw new Error("unknown item in stream!");
|
||||
}
|
||||
var shouldUnpack = shouldUnpackFile(file);
|
||||
insertFile(file.relative, { size: file.contents.length, mode: file.stat.mode }, shouldUnpack);
|
||||
if (shouldUnpack) {
|
||||
// The file goes outside of xx.asar, in a folder xx.asar.unpacked
|
||||
var relative = path.relative(folderPath, file.path);
|
||||
this.queue(new VinylFile({
|
||||
cwd: folderPath,
|
||||
base: folderPath,
|
||||
path: path.join(destFilename + '.unpacked', relative),
|
||||
stat: file.stat,
|
||||
contents: file.contents
|
||||
}));
|
||||
}
|
||||
else {
|
||||
// The file goes inside of xx.asar
|
||||
out.push(file.contents);
|
||||
}
|
||||
}, function () {
|
||||
var _this = this;
|
||||
var finish = function () {
|
||||
{
|
||||
var headerPickle = pickle.createEmpty();
|
||||
headerPickle.writeString(JSON.stringify(filesystem.header));
|
||||
var headerBuf = headerPickle.toBuffer();
|
||||
var sizePickle = pickle.createEmpty();
|
||||
sizePickle.writeUInt32(headerBuf.length);
|
||||
var sizeBuf = sizePickle.toBuffer();
|
||||
out.unshift(headerBuf);
|
||||
out.unshift(sizeBuf);
|
||||
}
|
||||
var contents = Buffer.concat(out);
|
||||
out.length = 0;
|
||||
_this.queue(new VinylFile({
|
||||
cwd: folderPath,
|
||||
base: folderPath,
|
||||
path: destFilename,
|
||||
contents: contents
|
||||
}));
|
||||
_this.queue(null);
|
||||
};
|
||||
// Call finish() only when all file inserts have finished...
|
||||
if (pendingInserts === 0) {
|
||||
finish();
|
||||
}
|
||||
else {
|
||||
onFileInserted = function () {
|
||||
pendingInserts--;
|
||||
if (pendingInserts === 0) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.createAsar = createAsar;
|
||||
131
build/lib/asar.ts
Normal file
131
build/lib/asar.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as es from 'event-stream';
|
||||
import * as pickle from 'chromium-pickle-js';
|
||||
import * as Filesystem from 'asar/lib/filesystem';
|
||||
import * as VinylFile from 'vinyl';
|
||||
import * as minimatch from 'minimatch';
|
||||
|
||||
export function createAsar(folderPath: string, unpackGlobs: string[], destFilename: string): NodeJS.ReadWriteStream {
|
||||
|
||||
const shouldUnpackFile = (file: VinylFile): boolean => {
|
||||
for (let i = 0; i < unpackGlobs.length; i++) {
|
||||
if (minimatch(file.relative, unpackGlobs[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const filesystem = new Filesystem(folderPath);
|
||||
const out: Buffer[] = [];
|
||||
|
||||
// Keep track of pending inserts
|
||||
let pendingInserts = 0;
|
||||
let onFileInserted = () => { pendingInserts--; };
|
||||
|
||||
// Do not insert twice the same directory
|
||||
const seenDir: { [key: string]: boolean; } = {};
|
||||
const insertDirectoryRecursive = (dir: string) => {
|
||||
if (seenDir[dir]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lastSlash = dir.lastIndexOf('/');
|
||||
if (lastSlash === -1) {
|
||||
lastSlash = dir.lastIndexOf('\\');
|
||||
}
|
||||
if (lastSlash !== -1) {
|
||||
insertDirectoryRecursive(dir.substring(0, lastSlash));
|
||||
}
|
||||
seenDir[dir] = true;
|
||||
filesystem.insertDirectory(dir);
|
||||
};
|
||||
|
||||
const insertDirectoryForFile = (file: string) => {
|
||||
let lastSlash = file.lastIndexOf('/');
|
||||
if (lastSlash === -1) {
|
||||
lastSlash = file.lastIndexOf('\\');
|
||||
}
|
||||
if (lastSlash !== -1) {
|
||||
insertDirectoryRecursive(file.substring(0, lastSlash));
|
||||
}
|
||||
};
|
||||
|
||||
const insertFile = (relativePath: string, stat: { size: number; mode: number; }, shouldUnpack: boolean) => {
|
||||
insertDirectoryForFile(relativePath);
|
||||
pendingInserts++;
|
||||
filesystem.insertFile(relativePath, shouldUnpack, { stat: stat }, {}, onFileInserted);
|
||||
};
|
||||
|
||||
return es.through(function (file) {
|
||||
if (file.stat.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
if (!file.stat.isFile()) {
|
||||
throw new Error(`unknown item in stream!`);
|
||||
}
|
||||
const shouldUnpack = shouldUnpackFile(file);
|
||||
insertFile(file.relative, { size: file.contents.length, mode: file.stat.mode }, shouldUnpack);
|
||||
|
||||
if (shouldUnpack) {
|
||||
// The file goes outside of xx.asar, in a folder xx.asar.unpacked
|
||||
const relative = path.relative(folderPath, file.path);
|
||||
this.queue(new VinylFile({
|
||||
cwd: folderPath,
|
||||
base: folderPath,
|
||||
path: path.join(destFilename + '.unpacked', relative),
|
||||
stat: file.stat,
|
||||
contents: file.contents
|
||||
}));
|
||||
} else {
|
||||
// The file goes inside of xx.asar
|
||||
out.push(file.contents);
|
||||
}
|
||||
}, function () {
|
||||
|
||||
let finish = () => {
|
||||
{
|
||||
const headerPickle = pickle.createEmpty();
|
||||
headerPickle.writeString(JSON.stringify(filesystem.header));
|
||||
const headerBuf = headerPickle.toBuffer();
|
||||
|
||||
const sizePickle = pickle.createEmpty();
|
||||
sizePickle.writeUInt32(headerBuf.length);
|
||||
const sizeBuf = sizePickle.toBuffer();
|
||||
|
||||
out.unshift(headerBuf);
|
||||
out.unshift(sizeBuf);
|
||||
}
|
||||
|
||||
const contents = Buffer.concat(out);
|
||||
out.length = 0;
|
||||
|
||||
this.queue(new VinylFile({
|
||||
cwd: folderPath,
|
||||
base: folderPath,
|
||||
path: destFilename,
|
||||
contents: contents
|
||||
}));
|
||||
this.queue(null);
|
||||
};
|
||||
|
||||
// Call finish() only when all file inserts have finished...
|
||||
if (pendingInserts === 0) {
|
||||
finish();
|
||||
} else {
|
||||
onFileInserted = () => {
|
||||
pendingInserts--;
|
||||
if (pendingInserts === 0) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
122
build/lib/builtInExtensions.js
Normal file
122
build/lib/builtInExtensions.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const mkdirp = require('mkdirp');
|
||||
const rimraf = require('rimraf');
|
||||
const es = require('event-stream');
|
||||
const rename = require('gulp-rename');
|
||||
const vfs = require('vinyl-fs');
|
||||
const ext = require('./extensions');
|
||||
const util = require('gulp-util');
|
||||
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const builtInExtensions = require('../builtInExtensions.json');
|
||||
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
|
||||
function getExtensionPath(extension) {
|
||||
return path.join(root, '.build', 'builtInExtensions', extension.name);
|
||||
}
|
||||
|
||||
function isUpToDate(extension) {
|
||||
const packagePath = path.join(getExtensionPath(extension), 'package.json');
|
||||
|
||||
if (!fs.existsSync(packagePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const packageContents = fs.readFileSync(packagePath, { encoding: 'utf8' });
|
||||
|
||||
try {
|
||||
const diskVersion = JSON.parse(packageContents).version;
|
||||
return (diskVersion === extension.version);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function syncMarketplaceExtension(extension) {
|
||||
if (isUpToDate(extension)) {
|
||||
util.log(util.colors.blue('[marketplace]'), `${extension.name}@${extension.version}`, util.colors.green('✔︎'));
|
||||
return es.readArray([]);
|
||||
}
|
||||
|
||||
rimraf.sync(getExtensionPath(extension));
|
||||
|
||||
return ext.fromMarketplace(extension.name, extension.version)
|
||||
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`))
|
||||
.pipe(vfs.dest('.build/builtInExtensions'))
|
||||
.on('end', () => util.log(util.colors.blue('[marketplace]'), extension.name, util.colors.green('✔︎')));
|
||||
}
|
||||
|
||||
function syncExtension(extension, controlState) {
|
||||
switch (controlState) {
|
||||
case 'disabled':
|
||||
util.log(util.colors.blue('[disabled]'), util.colors.gray(extension.name));
|
||||
return es.readArray([]);
|
||||
|
||||
case 'marketplace':
|
||||
return syncMarketplaceExtension(extension);
|
||||
|
||||
default:
|
||||
if (!fs.existsSync(controlState)) {
|
||||
util.log(util.colors.red(`Error: Built-in extension '${extension.name}' is configured to run from '${controlState}' but that path does not exist.`));
|
||||
return es.readArray([]);
|
||||
|
||||
} else if (!fs.existsSync(path.join(controlState, 'package.json'))) {
|
||||
util.log(util.colors.red(`Error: Built-in extension '${extension.name}' is configured to run from '${controlState}' but there is no 'package.json' file in that directory.`));
|
||||
return es.readArray([]);
|
||||
}
|
||||
|
||||
util.log(util.colors.blue('[local]'), `${extension.name}: ${util.colors.cyan(controlState)}`, util.colors.green('✔︎'));
|
||||
return es.readArray([]);
|
||||
}
|
||||
}
|
||||
|
||||
function readControlFile() {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(controlFilePath, 'utf8'));
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function writeControlFile(control) {
|
||||
mkdirp.sync(path.dirname(controlFilePath));
|
||||
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
|
||||
}
|
||||
|
||||
function main() {
|
||||
util.log('Syncronizing built-in extensions...');
|
||||
util.log(`You can manage built-in extensions with the ${util.colors.cyan('--builtin')} flag`);
|
||||
|
||||
const control = readControlFile();
|
||||
const streams = [];
|
||||
|
||||
for (const extension of builtInExtensions) {
|
||||
let controlState = control[extension.name] || 'marketplace';
|
||||
control[extension.name] = controlState;
|
||||
|
||||
streams.push(syncExtension(extension, controlState));
|
||||
}
|
||||
|
||||
writeControlFile(control);
|
||||
|
||||
es.merge(streams)
|
||||
.on('error', err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
})
|
||||
.on('end', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -217,6 +217,7 @@ function removeDuplicateTSBoilerplate(destFiles) {
|
||||
{ start: /^var __metadata/, end: /^};$/ },
|
||||
{ start: /^var __param/, end: /^};$/ },
|
||||
{ start: /^var __awaiter/, end: /^};$/ },
|
||||
{ start: /^var __generator/, end: /^};$/ },
|
||||
];
|
||||
destFiles.forEach(function (destFile) {
|
||||
var SEEN_BOILERPLATE = [];
|
||||
|
||||
@@ -44,11 +44,11 @@ interface ILoaderPluginReqFunc {
|
||||
|
||||
export interface IEntryPoint {
|
||||
name: string;
|
||||
include: string[];
|
||||
exclude: string[];
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
prepend: string[];
|
||||
append: string[];
|
||||
dest: string;
|
||||
append?: string[];
|
||||
dest?: string;
|
||||
}
|
||||
|
||||
interface IEntryPointMap {
|
||||
@@ -339,6 +339,7 @@ function removeDuplicateTSBoilerplate(destFiles: IConcatFile[]): IConcatFile[] {
|
||||
{ start: /^var __metadata/, end: /^};$/ },
|
||||
{ start: /^var __param/, end: /^};$/ },
|
||||
{ start: /^var __awaiter/, end: /^};$/ },
|
||||
{ start: /^var __generator/, end: /^};$/ },
|
||||
];
|
||||
|
||||
destFiles.forEach((destFile) => {
|
||||
|
||||
@@ -22,6 +22,9 @@ var rootDir = path.join(__dirname, '../../src');
|
||||
var options = require('../../src/tsconfig.json').compilerOptions;
|
||||
options.verbose = false;
|
||||
options.sourceMap = true;
|
||||
if (process.env['VSCODE_NO_SOURCEMAP']) {
|
||||
options.sourceMap = false;
|
||||
}
|
||||
options.rootDir = rootDir;
|
||||
options.sourceRoot = util.toFileUri(rootDir);
|
||||
function createCompile(build, emitError) {
|
||||
@@ -58,9 +61,13 @@ function compileTask(out, build) {
|
||||
return function () {
|
||||
var compile = createCompile(build, true);
|
||||
var src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
|
||||
// Do not write .d.ts files to disk, as they are not needed there.
|
||||
var dtsFilter = util.filter(function (data) { return !/\.d\.ts$/.test(data.path); });
|
||||
return src
|
||||
.pipe(compile())
|
||||
.pipe(dtsFilter)
|
||||
.pipe(gulp.dest(out))
|
||||
.pipe(dtsFilter.restore)
|
||||
.pipe(monacodtsTask(out, false));
|
||||
};
|
||||
}
|
||||
@@ -70,54 +77,19 @@ function watchTask(out, build) {
|
||||
var compile = createCompile(build);
|
||||
var src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
|
||||
var watchSrc = watch('src/**', { base: 'src' });
|
||||
// Do not write .d.ts files to disk, as they are not needed there.
|
||||
var dtsFilter = util.filter(function (data) { return !/\.d\.ts$/.test(data.path); });
|
||||
return watchSrc
|
||||
.pipe(util.incremental(compile, src, true))
|
||||
.pipe(dtsFilter)
|
||||
.pipe(gulp.dest(out))
|
||||
.pipe(dtsFilter.restore)
|
||||
.pipe(monacodtsTask(out, true));
|
||||
};
|
||||
}
|
||||
exports.watchTask = watchTask;
|
||||
function reloadTypeScriptNodeModule() {
|
||||
var util = require('gulp-util');
|
||||
function log(message) {
|
||||
var rest = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
rest[_i - 1] = arguments[_i];
|
||||
}
|
||||
util.log.apply(util, [util.colors.cyan('[memory watch dog]'), message].concat(rest));
|
||||
}
|
||||
function heapUsed() {
|
||||
return (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + ' MB';
|
||||
}
|
||||
return es.through(function (data) {
|
||||
this.emit('data', data);
|
||||
}, function () {
|
||||
log('memory usage after compilation finished: ' + heapUsed());
|
||||
// It appears we are running into some variant of
|
||||
// https://bugs.chromium.org/p/v8/issues/detail?id=2073
|
||||
//
|
||||
// Even though all references are dropped, some
|
||||
// optimized methods in the TS compiler end up holding references
|
||||
// to the entire TypeScript language host (>600MB)
|
||||
//
|
||||
// The idea is to force v8 to drop references to these
|
||||
// optimized methods, by "reloading" the typescript node module
|
||||
log('Reloading typescript node module...');
|
||||
var resolvedName = require.resolve('typescript');
|
||||
var originalModule = require.cache[resolvedName];
|
||||
delete require.cache[resolvedName];
|
||||
var newExports = require('typescript');
|
||||
require.cache[resolvedName] = originalModule;
|
||||
for (var prop in newExports) {
|
||||
if (newExports.hasOwnProperty(prop)) {
|
||||
originalModule.exports[prop] = newExports[prop];
|
||||
}
|
||||
}
|
||||
log('typescript node module reloaded.');
|
||||
this.emit('end');
|
||||
});
|
||||
}
|
||||
function monacodtsTask(out, isWatch) {
|
||||
var basePath = path.resolve(process.cwd(), out);
|
||||
var neededFiles = {};
|
||||
monacodts.getFilesToWatch(out).forEach(function (filePath) {
|
||||
filePath = path.normalize(filePath);
|
||||
@@ -160,7 +132,7 @@ function monacodtsTask(out, isWatch) {
|
||||
}));
|
||||
}
|
||||
resultStream = es.through(function (data) {
|
||||
var filePath = path.normalize(data.path);
|
||||
var filePath = path.normalize(path.resolve(basePath, data.relative));
|
||||
if (neededFiles[filePath]) {
|
||||
setInputFile(filePath, data.contents.toString());
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ const rootDir = path.join(__dirname, '../../src');
|
||||
const options = require('../../src/tsconfig.json').compilerOptions;
|
||||
options.verbose = false;
|
||||
options.sourceMap = true;
|
||||
if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
|
||||
options.sourceMap = false;
|
||||
}
|
||||
options.rootDir = rootDir;
|
||||
options.sourceRoot = util.toFileUri(rootDir);
|
||||
|
||||
@@ -49,7 +52,6 @@ function createCompile(build: boolean, emitError?: boolean): (token?: util.ICanc
|
||||
.pipe(tsFilter)
|
||||
.pipe(util.loadSourcemaps())
|
||||
.pipe(ts(token))
|
||||
// .pipe(build ? reloadTypeScriptNodeModule() : es.through())
|
||||
.pipe(noDeclarationsFilter)
|
||||
.pipe(build ? nls() : es.through())
|
||||
.pipe(noDeclarationsFilter.restore)
|
||||
@@ -75,9 +77,14 @@ export function compileTask(out: string, build: boolean): () => NodeJS.ReadWrite
|
||||
gulp.src('node_modules/typescript/lib/lib.d.ts'),
|
||||
);
|
||||
|
||||
// Do not write .d.ts files to disk, as they are not needed there.
|
||||
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
|
||||
|
||||
return src
|
||||
.pipe(compile())
|
||||
.pipe(dtsFilter)
|
||||
.pipe(gulp.dest(out))
|
||||
.pipe(dtsFilter.restore)
|
||||
.pipe(monacodtsTask(out, false));
|
||||
};
|
||||
}
|
||||
@@ -93,62 +100,22 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt
|
||||
);
|
||||
const watchSrc = watch('src/**', { base: 'src' });
|
||||
|
||||
// Do not write .d.ts files to disk, as they are not needed there.
|
||||
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
|
||||
|
||||
return watchSrc
|
||||
.pipe(util.incremental(compile, src, true))
|
||||
.pipe(dtsFilter)
|
||||
.pipe(gulp.dest(out))
|
||||
.pipe(dtsFilter.restore)
|
||||
.pipe(monacodtsTask(out, true));
|
||||
};
|
||||
}
|
||||
|
||||
function reloadTypeScriptNodeModule(): NodeJS.ReadWriteStream {
|
||||
var util = require('gulp-util');
|
||||
function log(message: any, ...rest: any[]): void {
|
||||
util.log(util.colors.cyan('[memory watch dog]'), message, ...rest);
|
||||
}
|
||||
|
||||
function heapUsed(): string {
|
||||
return (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + ' MB';
|
||||
}
|
||||
|
||||
return es.through(function (data) {
|
||||
this.emit('data', data);
|
||||
}, function () {
|
||||
|
||||
log('memory usage after compilation finished: ' + heapUsed());
|
||||
|
||||
// It appears we are running into some variant of
|
||||
// https://bugs.chromium.org/p/v8/issues/detail?id=2073
|
||||
//
|
||||
// Even though all references are dropped, some
|
||||
// optimized methods in the TS compiler end up holding references
|
||||
// to the entire TypeScript language host (>600MB)
|
||||
//
|
||||
// The idea is to force v8 to drop references to these
|
||||
// optimized methods, by "reloading" the typescript node module
|
||||
|
||||
log('Reloading typescript node module...');
|
||||
|
||||
var resolvedName = require.resolve('typescript');
|
||||
|
||||
var originalModule = require.cache[resolvedName];
|
||||
delete require.cache[resolvedName];
|
||||
var newExports = require('typescript');
|
||||
require.cache[resolvedName] = originalModule;
|
||||
|
||||
for (var prop in newExports) {
|
||||
if (newExports.hasOwnProperty(prop)) {
|
||||
originalModule.exports[prop] = newExports[prop];
|
||||
}
|
||||
}
|
||||
|
||||
log('typescript node module reloaded.');
|
||||
|
||||
this.emit('end');
|
||||
});
|
||||
}
|
||||
|
||||
function monacodtsTask(out: string, isWatch: boolean): NodeJS.ReadWriteStream {
|
||||
|
||||
const basePath = path.resolve(process.cwd(), out);
|
||||
|
||||
const neededFiles: { [file: string]: boolean; } = {};
|
||||
monacodts.getFilesToWatch(out).forEach(function (filePath) {
|
||||
filePath = path.normalize(filePath);
|
||||
@@ -196,7 +163,7 @@ function monacodtsTask(out: string, isWatch: boolean): NodeJS.ReadWriteStream {
|
||||
}
|
||||
|
||||
resultStream = es.through(function (data) {
|
||||
const filePath = path.normalize(data.path);
|
||||
const filePath = path.normalize(path.resolve(basePath, data.relative));
|
||||
if (neededFiles[filePath]) {
|
||||
setInputFile(filePath, data.contents.toString());
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,10 +46,6 @@
|
||||
"name": "vs/workbench/parts/execution",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/explorers",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/extensions",
|
||||
"project": "vscode-workbench"
|
||||
@@ -71,7 +67,11 @@
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/nps",
|
||||
"name": "vs/workbench/parts/localizations",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/logs",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
@@ -138,6 +138,10 @@
|
||||
"name": "vs/workbench/parts/welcome",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/actions",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/configuration",
|
||||
"project": "vscode-workbench"
|
||||
@@ -146,6 +150,10 @@
|
||||
"name": "vs/workbench/services/crashReporter",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/dialogs",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/editor",
|
||||
"project": "vscode-workbench"
|
||||
@@ -154,6 +162,10 @@
|
||||
"name": "vs/workbench/services/extensions",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/jsonschemas",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/files",
|
||||
"project": "vscode-workbench"
|
||||
@@ -162,10 +174,6 @@
|
||||
"name": "vs/workbench/services/keybinding",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/message",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/mode",
|
||||
"project": "vscode-workbench"
|
||||
@@ -193,10 +201,6 @@
|
||||
{
|
||||
"name": "vs/workbench/services/decorations",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "setup_messages",
|
||||
"project": "vscode-workbench"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
1030
build/lib/i18n.ts
1030
build/lib/i18n.ts
File diff suppressed because it is too large
Load Diff
@@ -79,7 +79,7 @@ function isImportNode(node) {
|
||||
function fileFrom(file, contents, path) {
|
||||
if (path === void 0) { path = file.path; }
|
||||
return new File({
|
||||
contents: new Buffer(contents),
|
||||
contents: Buffer.from(contents),
|
||||
base: file.base,
|
||||
cwd: file.cwd,
|
||||
path: path
|
||||
|
||||
@@ -131,7 +131,7 @@ module nls {
|
||||
|
||||
export function fileFrom(file: File, contents: string, path: string = file.path) {
|
||||
return new File({
|
||||
contents: new Buffer(contents),
|
||||
contents: Buffer.from(contents),
|
||||
base: file.base,
|
||||
cwd: file.cwd,
|
||||
path: path
|
||||
|
||||
@@ -59,7 +59,7 @@ function loader(bundledFileHeader, bundleLoader) {
|
||||
this.emit('data', new VinylFile({
|
||||
path: 'fake',
|
||||
base: '',
|
||||
contents: new Buffer(bundledFileHeader)
|
||||
contents: Buffer.from(bundledFileHeader)
|
||||
}));
|
||||
this.emit('data', data);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ function toConcatStream(bundledFileHeader, sources, dest) {
|
||||
return new VinylFile({
|
||||
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
|
||||
base: base,
|
||||
contents: new Buffer(source.contents)
|
||||
contents: Buffer.from(source.contents)
|
||||
});
|
||||
});
|
||||
return es.readArray(treatedSources)
|
||||
@@ -141,7 +141,7 @@ function optimizeTask(opts) {
|
||||
bundleInfoArray.push(new VinylFile({
|
||||
path: 'bundleInfo.json',
|
||||
base: '.',
|
||||
contents: new Buffer(JSON.stringify(result.bundleData, null, '\t'))
|
||||
contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
|
||||
}));
|
||||
}
|
||||
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
|
||||
@@ -174,7 +174,6 @@ function optimizeTask(opts) {
|
||||
};
|
||||
}
|
||||
exports.optimizeTask = optimizeTask;
|
||||
;
|
||||
/**
|
||||
* Wrap around uglify and allow the preserveComments function
|
||||
* to have a file "context" to include our copyright only once per file.
|
||||
@@ -237,4 +236,3 @@ function minifyTask(src, sourceMapBaseUrl) {
|
||||
};
|
||||
}
|
||||
exports.minifyTask = minifyTask;
|
||||
;
|
||||
|
||||
@@ -31,7 +31,7 @@ function log(prefix: string, message: string): void {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
export function loaderConfig(emptyPaths: string[]) {
|
||||
export function loaderConfig(emptyPaths?: string[]) {
|
||||
const result = {
|
||||
paths: {
|
||||
'vs': 'out-build/vs',
|
||||
@@ -73,7 +73,7 @@ function loader(bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWr
|
||||
this.emit('data', new VinylFile({
|
||||
path: 'fake',
|
||||
base: '',
|
||||
contents: new Buffer(bundledFileHeader)
|
||||
contents: Buffer.from(bundledFileHeader)
|
||||
}));
|
||||
this.emit('data', data);
|
||||
} else {
|
||||
@@ -117,7 +117,7 @@ function toConcatStream(bundledFileHeader: string, sources: bundle.IFile[], dest
|
||||
return new VinylFile({
|
||||
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
|
||||
base: base,
|
||||
contents: new Buffer(source.contents)
|
||||
contents: Buffer.from(source.contents)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -165,7 +165,7 @@ export interface IOptimizeTaskOpts {
|
||||
/**
|
||||
* (languages to process)
|
||||
*/
|
||||
languages: string[];
|
||||
languages: i18n.Language[];
|
||||
}
|
||||
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
|
||||
const entryPoints = opts.entryPoints;
|
||||
@@ -201,7 +201,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
|
||||
bundleInfoArray.push(new VinylFile({
|
||||
path: 'bundleInfo.json',
|
||||
base: '.',
|
||||
contents: new Buffer(JSON.stringify(result.bundleData, null, '\t'))
|
||||
contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
|
||||
}));
|
||||
}
|
||||
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
|
||||
@@ -241,7 +241,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
|
||||
}))
|
||||
.pipe(gulp.dest(out));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
declare class FileWithCopyright extends VinylFile {
|
||||
public __hasOurCopyright: boolean;
|
||||
@@ -295,7 +295,7 @@ function uglifyWithCopyrights(): NodeJS.ReadWriteStream {
|
||||
return es.duplex(input, output);
|
||||
}
|
||||
|
||||
export function minifyTask(src: string, sourceMapBaseUrl: string): (cb: any) => void {
|
||||
export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => void {
|
||||
const sourceMappingURL = sourceMapBaseUrl && (f => `${sourceMapBaseUrl}/${f.relative}.map`);
|
||||
|
||||
return cb => {
|
||||
@@ -326,4 +326,4 @@ export function minifyTask(src: string, sourceMapBaseUrl: string): (cb: any) =>
|
||||
cb(err);
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
9
build/lib/typings/event-stream.d.ts
vendored
9
build/lib/typings/event-stream.d.ts
vendored
@@ -1,7 +1,14 @@
|
||||
declare module "event-stream" {
|
||||
import { Stream } from 'stream';
|
||||
import { ThroughStream } from 'through';
|
||||
import { ThroughStream as _ThroughStream} from 'through';
|
||||
import { MapStream } from 'map-stream';
|
||||
import * as File from 'vinyl';
|
||||
|
||||
export interface ThroughStream extends _ThroughStream {
|
||||
queue(data: File | null);
|
||||
push(data: File | null);
|
||||
paused: boolean;
|
||||
}
|
||||
|
||||
function merge(streams: Stream[]): ThroughStream;
|
||||
function merge(...streams: Stream[]): ThroughStream;
|
||||
|
||||
@@ -143,7 +143,7 @@ function loadSourcemaps() {
|
||||
cb(null, f);
|
||||
return;
|
||||
}
|
||||
f.contents = new Buffer(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
|
||||
f.contents = Buffer.from(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
|
||||
fs.readFile(path.join(path.dirname(f.path), lastMatch[1]), 'utf8', function (err, contents) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
@@ -160,7 +160,7 @@ function stripSourceMappingURL() {
|
||||
var output = input
|
||||
.pipe(es.mapSync(function (f) {
|
||||
var contents = f.contents.toString('utf8');
|
||||
f.contents = new Buffer(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
|
||||
f.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
|
||||
return f;
|
||||
}));
|
||||
return es.duplex(input, output);
|
||||
@@ -173,7 +173,6 @@ function rimraf(dir) {
|
||||
if (!err) {
|
||||
return cb();
|
||||
}
|
||||
;
|
||||
if (err.code === 'ENOTEMPTY' && ++retries < 5) {
|
||||
return setTimeout(function () { return retry(cb); }, 10);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface IStreamProvider {
|
||||
(cancellationToken?: ICancellationToken): NodeJS.ReadWriteStream;
|
||||
}
|
||||
|
||||
export function incremental(streamProvider: IStreamProvider, initial: NodeJS.ReadWriteStream, supportsCancellation: boolean): NodeJS.ReadWriteStream {
|
||||
export function incremental(streamProvider: IStreamProvider, initial: NodeJS.ReadWriteStream, supportsCancellation?: boolean): NodeJS.ReadWriteStream {
|
||||
const input = es.through();
|
||||
const output = es.through();
|
||||
let state = 'idle';
|
||||
@@ -129,7 +129,7 @@ export function skipDirectories(): NodeJS.ReadWriteStream {
|
||||
});
|
||||
}
|
||||
|
||||
export function cleanNodeModule(name: string, excludes: string[], includes: string[]): NodeJS.ReadWriteStream {
|
||||
export function cleanNodeModule(name: string, excludes: string[], includes?: string[]): NodeJS.ReadWriteStream {
|
||||
const toGlob = (path: string) => '**/node_modules/' + name + (path ? '/' + path : '');
|
||||
const negate = (str: string) => '!' + str;
|
||||
|
||||
@@ -190,7 +190,7 @@ export function loadSourcemaps(): NodeJS.ReadWriteStream {
|
||||
return;
|
||||
}
|
||||
|
||||
f.contents = new Buffer(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
|
||||
f.contents = Buffer.from(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
|
||||
|
||||
fs.readFile(path.join(path.dirname(f.path), lastMatch[1]), 'utf8', (err, contents) => {
|
||||
if (err) { return cb(err); }
|
||||
@@ -209,7 +209,7 @@ export function stripSourceMappingURL(): NodeJS.ReadWriteStream {
|
||||
const output = input
|
||||
.pipe(es.mapSync<VinylFile, VinylFile>(f => {
|
||||
const contents = (<Buffer>f.contents).toString('utf8');
|
||||
f.contents = new Buffer(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
|
||||
f.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
|
||||
return f;
|
||||
}));
|
||||
|
||||
@@ -223,7 +223,7 @@ export function rimraf(dir: string): (cb: any) => void {
|
||||
_rimraf(dir, { maxBusyTries: 1 }, (err: any) => {
|
||||
if (!err) {
|
||||
return cb();
|
||||
};
|
||||
}
|
||||
|
||||
if (err.code === 'ENOTEMPTY' && ++retries < 5) {
|
||||
return setTimeout(() => retry(cb), 10);
|
||||
|
||||
@@ -9,7 +9,7 @@ const es = require('event-stream');
|
||||
function handleDeletions() {
|
||||
return es.mapSync(f => {
|
||||
if (/\.ts$/.test(f.relative) && !f.contents) {
|
||||
f.contents = new Buffer('');
|
||||
f.contents = Buffer.from('');
|
||||
f.stat = { mtime: new Date() };
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ function watch(root) {
|
||||
path: path,
|
||||
base: root
|
||||
});
|
||||
|
||||
//@ts-ignore
|
||||
file.event = type;
|
||||
result.emit('data', file);
|
||||
}
|
||||
|
||||
nsfw(root, function(events) {
|
||||
nsfw(root, function (events) {
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var e = events[i];
|
||||
var changeType = e.action;
|
||||
@@ -47,16 +47,16 @@ function watch(root) {
|
||||
handleEvent(path.join(e.directory, e.file), toChangeType(changeType));
|
||||
}
|
||||
}
|
||||
}).then(function(watcher) {
|
||||
}).then(function (watcher) {
|
||||
watcher.start();
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
var cache = Object.create(null);
|
||||
|
||||
module.exports = function(pattern, options) {
|
||||
module.exports = function (pattern, options) {
|
||||
options = options || {};
|
||||
|
||||
var cwd = path.normalize(options.cwd || process.cwd());
|
||||
@@ -66,7 +66,7 @@ module.exports = function(pattern, options) {
|
||||
watcher = cache[cwd] = watch(cwd);
|
||||
}
|
||||
|
||||
var rebase = !options.base ? es.through() : es.mapSync(function(f) {
|
||||
var rebase = !options.base ? es.through() : es.mapSync(function (f) {
|
||||
f.base = options.base;
|
||||
return f;
|
||||
});
|
||||
@@ -74,13 +74,13 @@ module.exports = function(pattern, options) {
|
||||
return watcher
|
||||
.pipe(filter(['**', '!.git{,/**}'])) // ignore all things git
|
||||
.pipe(filter(pattern))
|
||||
.pipe(es.map(function(file, cb) {
|
||||
fs.stat(file.path, function(err, stat) {
|
||||
.pipe(es.map(function (file, cb) {
|
||||
fs.stat(file.path, function (err, stat) {
|
||||
if (err && err.code === 'ENOENT') { return cb(null, file); }
|
||||
if (err) { return cb(); }
|
||||
if (!stat.isFile()) { return cb(); }
|
||||
|
||||
fs.readFile(file.path, function(err, contents) {
|
||||
fs.readFile(file.path, function (err, contents) {
|
||||
if (err && err.code === 'ENOENT') { return cb(null, file); }
|
||||
if (err) { return cb(); }
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ function watch(root) {
|
||||
var result = es.through();
|
||||
var child = cp.spawn(watcherPath, [root]);
|
||||
|
||||
child.stdout.on('data', function(data) {
|
||||
child.stdout.on('data', function (data) {
|
||||
// @ts-ignore
|
||||
var lines = data.toString('utf8').split('\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i].trim();
|
||||
@@ -46,17 +47,17 @@ function watch(root) {
|
||||
path: changePathFull,
|
||||
base: root
|
||||
});
|
||||
|
||||
//@ts-ignore
|
||||
file.event = toChangeType(changeType);
|
||||
result.emit('data', file);
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on('data', function(data) {
|
||||
child.stderr.on('data', function (data) {
|
||||
result.emit('error', data);
|
||||
});
|
||||
|
||||
child.on('exit', function(code) {
|
||||
child.on('exit', function (code) {
|
||||
result.emit('error', 'Watcher died with code ' + code);
|
||||
child = null;
|
||||
});
|
||||
@@ -70,7 +71,7 @@ function watch(root) {
|
||||
|
||||
var cache = Object.create(null);
|
||||
|
||||
module.exports = function(pattern, options) {
|
||||
module.exports = function (pattern, options) {
|
||||
options = options || {};
|
||||
|
||||
var cwd = path.normalize(options.cwd || process.cwd());
|
||||
|
||||
@@ -1 +1,21 @@
|
||||
See project root directory
|
||||
The Source EULA
|
||||
|
||||
Copyright (c) 2016 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.
|
||||
|
||||
@@ -32,7 +32,7 @@ END OF winjs NOTICES AND INFORMATION
|
||||
|
||||
%% string_scorer version 0.1.20 (https://github.com/joshaven/string_score)
|
||||
=========================================
|
||||
This software is released under the MIT license:
|
||||
This software is released under the Source EULA:
|
||||
|
||||
Copyright (c) Joshaven Potter
|
||||
|
||||
@@ -60,7 +60,7 @@ END OF string_scorer NOTICES AND INFORMATION
|
||||
|
||||
%% chjj-marked NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
The MIT License (MIT)
|
||||
The Source EULA
|
||||
|
||||
Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/)
|
||||
|
||||
|
||||
@@ -62,19 +62,24 @@ export interface ICommandHandler {
|
||||
#include(vs/editor/standalone/browser/colorizer): IColorizerOptions, IColorizerElementOptions
|
||||
#include(vs/base/common/scrollable): ScrollbarVisibility
|
||||
#include(vs/platform/theme/common/themeService): ThemeColor
|
||||
#includeAll(vs/editor/common/editorCommon;IMode=>languages.IMode;LanguageIdentifier=>languages.LanguageIdentifier;editorOptions.=>): ISelection, IScrollEvent
|
||||
#includeAll(vs/editor/common/model;LanguageIdentifier=>languages.LanguageIdentifier): IScrollEvent
|
||||
#includeAll(vs/editor/common/editorCommon;editorOptions.=>): IScrollEvent
|
||||
#includeAll(vs/editor/common/model/textModelEvents):
|
||||
#includeAll(vs/editor/common/controller/cursorEvents):
|
||||
#includeAll(vs/editor/common/config/editorOptions):
|
||||
#includeAll(vs/editor/browser/editorBrowser;editorCommon.=>;editorOptions.=>):
|
||||
#include(vs/editor/common/config/fontInfo): FontInfo, BareFontInfo
|
||||
|
||||
//compatibility:
|
||||
export type IReadOnlyModel = ITextModel;
|
||||
export type IModel = ITextModel;
|
||||
}
|
||||
|
||||
declare module monaco.languages {
|
||||
|
||||
#includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData):
|
||||
#includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;model.=>editor.;IMarkerData=>editor.IMarkerData):
|
||||
#includeAll(vs/editor/common/modes/languageConfiguration):
|
||||
#includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData):
|
||||
#includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData;model.=>editor.):
|
||||
#include(vs/editor/common/services/modeService): ILanguageExtensionPoint
|
||||
#includeAll(vs/editor/standalone/common/monarch/monarchTypes):
|
||||
|
||||
|
||||
@@ -21,16 +21,16 @@ function yarnInstall(location, opts) {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
yarnInstall('extensions-modules');
|
||||
yarnInstall('extensions'); // node modules shared by all extensions
|
||||
|
||||
const extensions = [
|
||||
'vscode-colorize-tests',
|
||||
'json',
|
||||
'mssql',
|
||||
'mssql',
|
||||
'configuration-editing',
|
||||
'extension-editing',
|
||||
'markdown',
|
||||
'markdown-basics',
|
||||
'git',
|
||||
'merge-conflict',
|
||||
'insights-default',
|
||||
@@ -43,6 +43,7 @@ extensions.forEach(extension => yarnInstall(`extensions/${extension}`));
|
||||
function yarnInstallBuildDependencies() {
|
||||
// make sure we install the deps of build/lib/watch for the system installed
|
||||
// node, since that is the driver of gulp
|
||||
//@ts-ignore
|
||||
const env = Object.assign({}, process.env);
|
||||
const watchPath = path.join(path.dirname(__dirname), 'lib', 'watch');
|
||||
const yarnrcPath = path.join(watchPath, '.yarnrc');
|
||||
@@ -60,4 +61,5 @@ runtime "${runtime}"`;
|
||||
}
|
||||
|
||||
yarnInstall(`build`); // node modules required for build
|
||||
yarnInstall('test/smoke'); // node modules required for smoketest
|
||||
yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron
|
||||
@@ -4,9 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const cp = require('child_process');
|
||||
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function updateGrammar(location) {
|
||||
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const result = cp.spawnSync(npm, ['run', 'update-grammar'], {
|
||||
cwd: location,
|
||||
stdio: 'inherit'
|
||||
@@ -17,50 +19,17 @@ function updateGrammar(location) {
|
||||
}
|
||||
}
|
||||
|
||||
const extensions = [
|
||||
'bat',
|
||||
'clojure',
|
||||
'coffeescript',
|
||||
'cpp',
|
||||
'csharp',
|
||||
'css',
|
||||
'diff',
|
||||
'docker',
|
||||
'fsharp',
|
||||
'gitsyntax',
|
||||
'go',
|
||||
'groovy',
|
||||
'handlebars',
|
||||
'hlsl',
|
||||
'html',
|
||||
'ini',
|
||||
'java',
|
||||
// 'javascript', updated through JavaScript
|
||||
'json',
|
||||
'less',
|
||||
'lua',
|
||||
'make',
|
||||
'markdown',
|
||||
'objective-c',
|
||||
'perl',
|
||||
'php',
|
||||
// 'powershell', grammar not ready yet, @daviwil will ping when ready
|
||||
'pug',
|
||||
'python',
|
||||
'r',
|
||||
'razor',
|
||||
'ruby',
|
||||
'rust',
|
||||
'scss',
|
||||
'shaderlab',
|
||||
'shellscript',
|
||||
'sql',
|
||||
'swift',
|
||||
'typescript',
|
||||
'vb',
|
||||
'xml',
|
||||
'yaml'
|
||||
];
|
||||
const allExtensionFolders = fs.readdirSync('extensions');
|
||||
const extensions = allExtensionFolders.filter(e => {
|
||||
try {
|
||||
let packageJSON = JSON.parse(fs.readFileSync(path.join('extensions', e, 'package.json')).toString());
|
||||
return packageJSON && packageJSON.scripts && packageJSON.scripts['update-grammar'];
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Updating ${extensions.length} grammars...`);
|
||||
|
||||
extensions.forEach(extension => updateGrammar(`extensions/${extension}`));
|
||||
|
||||
@@ -70,4 +39,5 @@ if (process.platform === 'win32') {
|
||||
cp.spawn('.\scripts\test-integration.bat', [], { env: process.env, stdio: 'inherit' });
|
||||
} else {
|
||||
cp.spawn('/bin/bash', ['./scripts/test-integration.sh'], { env: process.env, stdio: 'inherit' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,19 @@ var url = require('url');
|
||||
|
||||
function getOptions(urlString) {
|
||||
var _url = url.parse(urlString);
|
||||
var headers = {
|
||||
'User-Agent': 'VSCode'
|
||||
};
|
||||
var token = process.env['GITHUB_TOKEN'];
|
||||
if (token) {
|
||||
headers['Authorization'] = 'token ' + token
|
||||
}
|
||||
return {
|
||||
protocol: _url.protocol,
|
||||
host: _url.host,
|
||||
port: _url.port,
|
||||
path: _url.path,
|
||||
headers: {
|
||||
'User-Agent': 'NodeJS'
|
||||
}
|
||||
headers: headers
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,12 +37,16 @@ function download(url, redirectCount) {
|
||||
response.on('data', function (data) {
|
||||
content += data.toString();
|
||||
}).on('end', function () {
|
||||
if (response.statusCode === 403 && response.headers['x-ratelimit-remaining'] === '0') {
|
||||
e('GitHub API rate exceeded. Set GITHUB_TOKEN environment variable to increase rate limit.');
|
||||
return;
|
||||
}
|
||||
let count = redirectCount || 0;
|
||||
if (count < 5 && response.statusCode >= 300 && response.statusCode <= 303 || response.statusCode === 307) {
|
||||
let location = response.headers['location'];
|
||||
if (location) {
|
||||
console.log("Redirected " + url + " to " + location);
|
||||
download(location, count+1).then(c, e);
|
||||
download(location, count + 1).then(c, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -59,17 +68,13 @@ function getCommitSha(repoId, repoPath) {
|
||||
commitDate: lastCommit.commit.author.date
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Failed extracting the SHA: " + content);
|
||||
return Promise.resolve(null);
|
||||
return Promise.reject(new Error("Failed extracting the SHA: " + content));
|
||||
}
|
||||
}, function () {
|
||||
console.error('Failed loading ' + commitInfo);
|
||||
return Promise.resolve(null);
|
||||
});
|
||||
}
|
||||
|
||||
exports.update = function (repoId, repoPath, dest, modifyGrammar) {
|
||||
var contentPath = 'https://raw.githubusercontent.com/' + repoId + '/master/' + repoPath;
|
||||
exports.update = function (repoId, repoPath, dest, modifyGrammar, version = 'master') {
|
||||
var contentPath = 'https://raw.githubusercontent.com/' + repoId + `/${version}/` + repoPath;
|
||||
console.log('Reading from ' + contentPath);
|
||||
return download(contentPath).then(function (content) {
|
||||
var ext = path.extname(repoPath);
|
||||
@@ -81,8 +86,7 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) {
|
||||
} else if (ext === '.json') {
|
||||
grammar = JSON.parse(content);
|
||||
} else {
|
||||
console.error('Unknown file extension: ' + ext);
|
||||
return;
|
||||
return Promise.reject(new Error('Unknown file extension: ' + ext));
|
||||
}
|
||||
if (modifyGrammar) {
|
||||
modifyGrammar(grammar);
|
||||
@@ -99,8 +103,10 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) {
|
||||
if (info) {
|
||||
result.version = 'https://github.com/' + repoId + '/commit/' + info.commitSha;
|
||||
}
|
||||
for (let key in grammar) {
|
||||
if (!result.hasOwnProperty(key)) {
|
||||
|
||||
let keys = ['name', 'scopeName', 'comment', 'injections', 'patterns', 'repository'];
|
||||
for (let key of keys) {
|
||||
if (grammar.hasOwnProperty(key)) {
|
||||
result[key] = grammar[key];
|
||||
}
|
||||
}
|
||||
@@ -113,11 +119,14 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) {
|
||||
console.log('Updated ' + path.basename(dest));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return Promise.reject(e);
|
||||
}
|
||||
});
|
||||
|
||||
}, console.error);
|
||||
}, console.error).catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
};
|
||||
|
||||
if (path.basename(process.argv[1]) === 'update-grammar.js') {
|
||||
|
||||
69
build/npm/update-localization-extension.js
Normal file
69
build/npm/update-localization-extension.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
let i18n = require("../lib/i18n");
|
||||
|
||||
let fs = require("fs");
|
||||
let path = require("path");
|
||||
let vfs = require("vinyl-fs");
|
||||
let rimraf = require('rimraf');
|
||||
|
||||
function update(idOrPath) {
|
||||
if (!idOrPath) {
|
||||
throw new Error('Argument must be the location of the localization extension.');
|
||||
}
|
||||
let locExtFolder = idOrPath;
|
||||
if (/^\w{2}(-\w+)?$/.test(idOrPath)) {
|
||||
locExtFolder = '../vscode-language-pack-' + idOrPath;
|
||||
}
|
||||
let locExtStat = fs.statSync(locExtFolder);
|
||||
if (!locExtStat || !locExtStat.isDirectory) {
|
||||
throw new Error('No directory found at ' + idOrPath);
|
||||
}
|
||||
let packageJSON = JSON.parse(fs.readFileSync(path.join(locExtFolder, 'package.json')).toString());
|
||||
let contributes = packageJSON['contributes'];
|
||||
if (!contributes) {
|
||||
throw new Error('The extension must define a "localizations" contribution in the "package.json"');
|
||||
}
|
||||
let localizations = contributes['localizations'];
|
||||
if (!localizations) {
|
||||
throw new Error('The extension must define a "localizations" contribution of type array in the "package.json"');
|
||||
}
|
||||
|
||||
localizations.forEach(function (localization) {
|
||||
if (!localization.languageId || !localization.languageName || !localization.localizedLanguageName) {
|
||||
throw new Error('Each localization contribution must define "languageId", "languageName" and "localizedLanguageName" properties.');
|
||||
}
|
||||
let server = localization.server || 'www.transifex.com';
|
||||
let userName = localization.userName || 'api';
|
||||
let apiToken = process.env.TRANSIFEX_API_TOKEN;
|
||||
let languageId = localization.transifexId || localization.languageId;
|
||||
let translationDataFolder = path.join(locExtFolder, 'translations');
|
||||
|
||||
if (fs.existsSync(translationDataFolder) && fs.existsSync(path.join(translationDataFolder, 'main.i18n.json'))) {
|
||||
console.log('Clearing \'' + translationDataFolder + '\'...');
|
||||
rimraf.sync(translationDataFolder);
|
||||
}
|
||||
|
||||
console.log('Downloading translations for \'' + languageId + '\' to \'' + translationDataFolder + '\'...');
|
||||
const translationPaths = [];
|
||||
i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths)
|
||||
.pipe(vfs.dest(translationDataFolder)).on('end', function () {
|
||||
localization.translations = [];
|
||||
for (let tp of translationPaths) {
|
||||
localization.translations.push({ id: tp.id, path: `./translations/${tp.resourceName}`});
|
||||
}
|
||||
fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t'));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
if (path.basename(process.argv[1]) === 'update-localization-extension.js') {
|
||||
update(process.argv[2]);
|
||||
}
|
||||
@@ -12,17 +12,18 @@
|
||||
"azure-storage": "^2.1.0",
|
||||
"decompress": "^4.2.0",
|
||||
"documentdb": "1.13.0",
|
||||
"extensions-modules": "file:../extensions-modules",
|
||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.2",
|
||||
"fs-extra-promise": "^1.0.1",
|
||||
"mime": "^1.3.4",
|
||||
"minimist": "^1.2.0",
|
||||
"typescript": "2.6.1",
|
||||
"vscode": "^1.0.1",
|
||||
"vscode": "^1.0.1",
|
||||
"xml2js": "^0.4.17"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc",
|
||||
"watch": "tsc --watch",
|
||||
"postinstall": "npm run compile"
|
||||
"compile": "tsc -p tsconfig.build.json",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"postinstall": "npm run compile",
|
||||
"npmCheckJs": "tsc --noEmit"
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@ set -e
|
||||
# setup nvm
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
export NVM_DIR=~/.nvm
|
||||
source $(brew --prefix nvm)/nvm.sh
|
||||
source $(brew --prefix nvm)/nvm.sh --no-use
|
||||
else
|
||||
source $NVM_DIR/nvm.sh
|
||||
source $NVM_DIR/nvm.sh --no-use
|
||||
fi
|
||||
|
||||
# install node
|
||||
|
||||
@@ -70,6 +70,7 @@ interface Asset {
|
||||
hash: string;
|
||||
sha256hash: string;
|
||||
size: number;
|
||||
supportsFastUpdate?: boolean;
|
||||
}
|
||||
|
||||
function createOrUpdate(commit: string, quality: string, platform: string, type: string, release: NewDocument, asset: Asset, isUpdate: boolean): Promise<void> {
|
||||
@@ -203,17 +204,30 @@ async function publish(commit: string, quality: string, platform: string, type:
|
||||
// mooncake is fussy and far away, this is needed!
|
||||
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
|
||||
|
||||
await assertContainer(mooncakeBlobService, quality);
|
||||
await Promise.all([
|
||||
assertContainer(blobService, quality),
|
||||
assertContainer(mooncakeBlobService, quality)
|
||||
]);
|
||||
|
||||
const mooncakeBlobExists = await doesAssetExist(mooncakeBlobService, quality, blobName);
|
||||
const [blobExists, moooncakeBlobExists] = await Promise.all([
|
||||
doesAssetExist(blobService, quality, blobName),
|
||||
doesAssetExist(mooncakeBlobService, quality, blobName)
|
||||
]);
|
||||
|
||||
if (!mooncakeBlobExists) {
|
||||
const promises = [];
|
||||
|
||||
if (!blobExists) {
|
||||
promises.push(uploadBlob(blobService, quality, blobName, file));
|
||||
}
|
||||
|
||||
if (!moooncakeBlobExists) {
|
||||
promises.push(uploadBlob(mooncakeBlobService, quality, blobName, file));
|
||||
}
|
||||
} else {
|
||||
console.log('Skipping Mooncake publishing.');
|
||||
}
|
||||
|
||||
|
||||
if (promises.length === 0) {
|
||||
console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`);
|
||||
return;
|
||||
@@ -240,6 +254,13 @@ async function publish(commit: string, quality: string, platform: string, type:
|
||||
size
|
||||
};
|
||||
|
||||
// Remove this if we ever need to rollback fast updates for windows
|
||||
if (/win32/.test(platform)) {
|
||||
asset.supportsFastUpdate = true;
|
||||
}
|
||||
|
||||
console.log('Asset:', JSON.stringify(asset, null, ' '));
|
||||
|
||||
const release = {
|
||||
id: commit,
|
||||
timestamp: (new Date()).getTime(),
|
||||
|
||||
@@ -19,6 +19,9 @@ step "Install dependencies" \
|
||||
step "Hygiene" \
|
||||
npm run gulp -- hygiene
|
||||
|
||||
step "Monaco Editor Check" \
|
||||
./node_modules/.bin/tsc -p ./src/tsconfig.monaco.json --noEmit
|
||||
|
||||
step "Mix in repository from vscode-distro" \
|
||||
npm run gulp -- mixin
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ step "Install dependencies" \
|
||||
step "Hygiene" \
|
||||
npm run gulp -- hygiene
|
||||
|
||||
step "Monaco Editor Check" \
|
||||
./node_modules/.bin/tsc -p ./src/tsconfig.monaco.json --noEmit
|
||||
|
||||
step "Mix in repository from vscode-distro" \
|
||||
npm run gulp -- mixin
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ step "Hygiene" {
|
||||
exec { & npm run gulp -- hygiene }
|
||||
}
|
||||
|
||||
step "Monaco Editor Check" {
|
||||
exec { & .\node_modules\.bin\tsc -p .\src\tsconfig.monaco.json --noEmit }
|
||||
}
|
||||
|
||||
$env:VSCODE_MIXIN_PASSWORD = $mixinPassword
|
||||
step "Mix in repository from vscode-distro" {
|
||||
exec { & npm run gulp -- mixin }
|
||||
@@ -41,6 +45,10 @@ step "Build minified" {
|
||||
exec { & npm run gulp -- "vscode-win32-$global:arch-min" }
|
||||
}
|
||||
|
||||
step "Copy Inno updater" {
|
||||
exec { & npm run gulp -- "vscode-win32-$global:arch-copy-inno-updater" }
|
||||
}
|
||||
|
||||
# step "Create loader snapshot" {
|
||||
# exec { & node build\lib\snapshotLoader.js --arch=$global:arch }
|
||||
# }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# install node
|
||||
$env:Path = $env:NVM_HOME + ";" + $env:NVM_SYMLINK + ";" + $env:Path
|
||||
$NodeVersion = "8.9.1"
|
||||
nvm install $NodeVersion
|
||||
nvm use $NodeVersion
|
||||
npm install -g yarn
|
||||
# nvm install $NodeVersion
|
||||
# nvm use $NodeVersion
|
||||
# npm install -g yarn
|
||||
$env:Path = $env:NVM_HOME + "\v" + $NodeVersion + ";" + $env:Path
|
||||
7
build/tsconfig.build.json
Normal file
7
build/tsconfig.build.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": false,
|
||||
"checkJs": false
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,12 @@
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": false,
|
||||
"experimentalDecorators": true,
|
||||
"newLine": "LF"
|
||||
"newLine": "LF",
|
||||
// enable JavaScript type checking for the language service
|
||||
// use the tsconfig.build.json for compiling wich disable JavaScript
|
||||
// type checking so that JavaScript file are not transpiled
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules/**"
|
||||
|
||||
@@ -9,5 +9,6 @@
|
||||
"always"
|
||||
],
|
||||
"triple-equals": true
|
||||
}
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
||||
1794
build/win32/OSSREADME.json
Normal file
1794
build/win32/OSSREADME.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ OutputDir={#OutputDir}
|
||||
OutputBaseFilename=SqlOpsStudioSetup
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
AppMutex={#AppMutex}
|
||||
AppMutex={code:GetAppMutex}
|
||||
SetupMutex={#AppMutex}setup
|
||||
WizardImageFile={#RepoDir}\resources\win32\inno-big.bmp
|
||||
WizardSmallImageFile={#RepoDir}\resources\win32\inno-small.bmp
|
||||
@@ -52,8 +52,13 @@ Type: filesandordirs; Name: "{app}\resources\app\out"; Check: IsNotUpdate
|
||||
Type: filesandordirs; Name: "{app}\resources\app\plugins"; Check: IsNotUpdate
|
||||
Type: filesandordirs; Name: "{app}\resources\app\extensions"; Check: IsNotUpdate
|
||||
Type: filesandordirs; Name: "{app}\resources\app\node_modules"; Check: IsNotUpdate
|
||||
Type: filesandordirs; Name: "{app}\resources\app\node_modules.asar.unpacked"; Check: IsNotUpdate
|
||||
Type: files; Name: "{app}\resources\app\node_modules.asar"; Check: IsNotUpdate
|
||||
Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNotUpdate
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: "{app}\_"
|
||||
|
||||
[Tasks]
|
||||
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
|
||||
Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}"
|
||||
@@ -138,6 +143,48 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function GetAppMutex(Value: string): string;
|
||||
begin
|
||||
if IsBackgroundUpdate() then
|
||||
Result := ''
|
||||
else
|
||||
Result := '{#AppMutex}';
|
||||
end;
|
||||
|
||||
function GetDestDir(Value: string): string;
|
||||
begin
|
||||
if IsBackgroundUpdate() then
|
||||
Result := ExpandConstant('{app}\_')
|
||||
else
|
||||
Result := ExpandConstant('{app}');
|
||||
end;
|
||||
|
||||
function BoolToStr(Value: Boolean): String;
|
||||
begin
|
||||
if Value then
|
||||
Result := 'true'
|
||||
else
|
||||
Result := 'false';
|
||||
end;
|
||||
|
||||
procedure CurStepChanged(CurStep: TSetupStep);
|
||||
var
|
||||
UpdateResultCode: Integer;
|
||||
begin
|
||||
if IsBackgroundUpdate() and (CurStep = ssPostInstall) then
|
||||
begin
|
||||
CreateMutex('{#AppMutex}-ready');
|
||||
|
||||
while (CheckForMutexes('{#AppMutex}')) do
|
||||
begin
|
||||
Log('Application is still running, waiting');
|
||||
Sleep(1000);
|
||||
end;
|
||||
|
||||
Exec(ExpandConstant('{app}\tools\inno_updater.exe'), ExpandConstant('"{app}\{#ExeBasename}.exe" ' + BoolToStr(LockFileExists())), '', SW_SHOW, ewWaitUntilTerminated, UpdateResultCode);
|
||||
end;
|
||||
end;
|
||||
|
||||
// http://stackoverflow.com/a/23838239/261019
|
||||
procedure Explode(var Dest: TArrayOfString; Text: String; Separator: String);
|
||||
var
|
||||
|
||||
BIN
build/win32/inno_updater.exe
Normal file
BIN
build/win32/inno_updater.exe
Normal file
Binary file not shown.
BIN
build/win32/vcruntime140.dll
Normal file
BIN
build/win32/vcruntime140.dll
Normal file
Binary file not shown.
4339
build/yarn.lock
4339
build/yarn.lock
File diff suppressed because it is too large
Load Diff
3
extensions-modules/.gitignore
vendored
3
extensions-modules/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
node_modules
|
||||
lib
|
||||
*.log
|
||||
@@ -1,9 +0,0 @@
|
||||
.vscode/
|
||||
lib/test/
|
||||
lib/**/*.map
|
||||
src/
|
||||
test/
|
||||
.eslintrc
|
||||
.gitignore
|
||||
gulpfile.js
|
||||
tsd.json
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "extensions-modules",
|
||||
"version": "0.1.0",
|
||||
"description": "Shared modules for SQL Operations Studio extensions",
|
||||
"dependencies": {
|
||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.1.5",
|
||||
"decompress": "^4.2.0",
|
||||
"fs-extra-promise": "^1.0.1",
|
||||
"http-proxy-agent": "^2.0.0",
|
||||
"https-proxy-agent": "^2.1.0",
|
||||
"opener": "^1.4.3",
|
||||
"tmp": "0.0.33",
|
||||
"vscode-extension-telemetry": "0.0.8",
|
||||
"vscode-languageclient": "3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^6.0.61",
|
||||
"vscode": "^1.1.10",
|
||||
"sqlops": "github:anthonydresser/vscode-extension-vscode"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "node ./node_modules/vscode/bin/install && node ./node_modules/sqlops/bin/install && tsc -p ./src",
|
||||
"compile": "tsc -p ./src",
|
||||
"watch": "tsc -w -p ./src"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "*",
|
||||
"sqlops": "*"
|
||||
},
|
||||
"main": "./lib/main.js",
|
||||
"typings": "./lib/main"
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
import * as path from 'path';
|
||||
import { IConfig } from '../languageservice/interfaces';
|
||||
import { Constants } from '../models/constants';
|
||||
|
||||
/*
|
||||
* Config class handles getting values from config.json.
|
||||
*/
|
||||
export default class Config implements IConfig {
|
||||
private _configJsonContent: any = undefined;
|
||||
|
||||
private _extensionConfigSectionName: string = undefined;
|
||||
private _fromBuild: boolean = undefined;
|
||||
|
||||
constructor(extensionConfigSectionName: string, private path: string, fromBuild?: boolean) {
|
||||
this._extensionConfigSectionName = extensionConfigSectionName;
|
||||
this._fromBuild = fromBuild;
|
||||
}
|
||||
|
||||
public get configJsonContent(): any {
|
||||
if (this._configJsonContent === undefined) {
|
||||
this._configJsonContent = this.loadConfig();
|
||||
}
|
||||
return this._configJsonContent;
|
||||
}
|
||||
|
||||
public getDownloadUrl(): string {
|
||||
return this.getConfigValue(Constants.downloadUrlConfigKey);
|
||||
}
|
||||
|
||||
public getInstallDirectory(): string {
|
||||
return this.getConfigValue(Constants.installDirConfigKey);
|
||||
}
|
||||
|
||||
public getExecutableFiles(): string[] {
|
||||
return this.getConfigValue(Constants.executableFilesConfigKey);
|
||||
}
|
||||
|
||||
public getPackageVersion(): string {
|
||||
return this.getConfigValue(Constants.versionConfigKey);
|
||||
}
|
||||
|
||||
public getConfigValue(configKey: string): any {
|
||||
let json = this.configJsonContent;
|
||||
let toolsConfig = json[Constants.serviceConfigKey];
|
||||
let configValue: string = undefined;
|
||||
if (toolsConfig !== undefined) {
|
||||
configValue = toolsConfig[configKey];
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public getExtensionConfig(key: string, defaultValue?: any): any {
|
||||
let json = this.configJsonContent;
|
||||
let extensionConfig = json[this._extensionConfigSectionName];
|
||||
let configValue = extensionConfig[key];
|
||||
if (!configValue) {
|
||||
configValue = defaultValue;
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public getWorkspaceConfig(key: string, defaultValue?: any): any {
|
||||
let json = this.configJsonContent;
|
||||
let configValue = json[key];
|
||||
if (!configValue) {
|
||||
configValue = defaultValue;
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public loadConfig(): any {
|
||||
let configContent = undefined;
|
||||
if (this._fromBuild) {
|
||||
let remainingPath = '../../../extensions/' + this._extensionConfigSectionName + '/client/out/config.json';
|
||||
configContent = fs.readFileSync(path.join(__dirname, remainingPath));
|
||||
}
|
||||
else {
|
||||
configContent = fs.readFileSync(this.path);
|
||||
}
|
||||
return JSON.parse(configContent);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import Config from './config';
|
||||
import { workspace, WorkspaceConfiguration } from 'vscode';
|
||||
import { IConfig } from '../languageservice/interfaces';
|
||||
import { Constants } from '../models/constants';
|
||||
|
||||
/*
|
||||
* ExtConfig class handles getting values from workspace config or config.json.
|
||||
*/
|
||||
export default class ExtConfig implements IConfig {
|
||||
|
||||
constructor(private _extensionConfigSectionName: string, private _config?: IConfig,
|
||||
path?: string,
|
||||
private _extensionConfig?: WorkspaceConfiguration,
|
||||
private _workspaceConfig?: WorkspaceConfiguration) {
|
||||
if (this._config === undefined) {
|
||||
this._config = new Config(_extensionConfigSectionName, path);
|
||||
}
|
||||
if (this._extensionConfig === undefined) {
|
||||
this._extensionConfig = workspace.getConfiguration(_extensionConfigSectionName);
|
||||
}
|
||||
if (this._workspaceConfig === undefined) {
|
||||
this._workspaceConfig = workspace.getConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
public getDownloadUrl(): string {
|
||||
return this.getConfigValue(Constants.downloadUrlConfigKey);
|
||||
}
|
||||
|
||||
public getInstallDirectory(): string {
|
||||
return this.getConfigValue(Constants.installDirConfigKey);
|
||||
}
|
||||
|
||||
public getExecutableFiles(): string[] {
|
||||
return this.getConfigValue(Constants.executableFilesConfigKey);
|
||||
}
|
||||
|
||||
public getPackageVersion(): string {
|
||||
return this.getConfigValue(Constants.versionConfigKey);
|
||||
}
|
||||
|
||||
public getConfigValue(configKey: string): any {
|
||||
let configValue: string = <string>this.getExtensionConfig(`${Constants.serviceConfigKey}.${configKey}`);
|
||||
if (!configValue) {
|
||||
configValue = this._config.getConfigValue(configKey);
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public getExtensionConfig(key: string, defaultValue?: any): any {
|
||||
let configValue = this._extensionConfig.get(key);
|
||||
if (configValue === undefined) {
|
||||
configValue = defaultValue;
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public getWorkspaceConfig(key: string, defaultValue?: any): any {
|
||||
let configValue = this._workspaceConfig.get(key);
|
||||
if (configValue === undefined) {
|
||||
configValue = defaultValue;
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public updateWorkspaceConfig(configKey: string, configValue: any) {
|
||||
this._workspaceConfig.update(configKey, configValue, true);
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import vscode = require('vscode');
|
||||
import { IExtensionConstants } from '../models/contracts/contracts';
|
||||
|
||||
export class VscodeWrapper {
|
||||
private _extensionConstants: IExtensionConstants;
|
||||
/**
|
||||
* Output channel for logging. Shared among all instances.
|
||||
*/
|
||||
private static _outputChannel: vscode.OutputChannel;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public constructor(constants: IExtensionConstants) {
|
||||
this._extensionConstants = constants;
|
||||
if (typeof VscodeWrapper._outputChannel === 'undefined') {
|
||||
VscodeWrapper._outputChannel = this.createOutputChannel(this._extensionConstants.outputChannelName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current active text editor
|
||||
*/
|
||||
public get activeTextEditor(): vscode.TextEditor {
|
||||
return vscode.window.activeTextEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current textDocument; any that are open?
|
||||
*/
|
||||
public get textDocuments(): vscode.TextDocument[] {
|
||||
return vscode.workspace.textDocuments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse uri
|
||||
*/
|
||||
public parseUri(uri: string): vscode.Uri {
|
||||
return vscode.Uri.parse(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI string for the current active text editor
|
||||
*/
|
||||
public get activeTextEditorUri(): string {
|
||||
if (typeof vscode.window.activeTextEditor !== 'undefined' &&
|
||||
typeof vscode.window.activeTextEditor.document !== 'undefined') {
|
||||
return vscode.window.activeTextEditor.document.uri.toString();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public get constants(): IExtensionConstants {
|
||||
return this._extensionConstants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an output channel in vscode.
|
||||
*/
|
||||
public createOutputChannel(channelName: string): vscode.OutputChannel {
|
||||
return vscode.window.createOutputChannel(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command denoted by the given command identifier.
|
||||
*
|
||||
* When executing an editor command not all types are allowed to
|
||||
* be passed as arguments. Allowed are the primitive types `string`, `boolean`,
|
||||
* `number`, `undefined`, and `null`, as well as classes defined in this API.
|
||||
* There are no restrictions when executing commands that have been contributed
|
||||
* by extensions.
|
||||
*
|
||||
* @param command Identifier of the command to execute.
|
||||
* @param rest Parameters passed to the command function.
|
||||
* @return A thenable that resolves to the returned value of the given command. `undefined` when
|
||||
* the command handler function doesn't return anything.
|
||||
* @see vscode.commands.executeCommand
|
||||
*/
|
||||
public executeCommand<T>(command: string, ...rest: any[]): Thenable<T> {
|
||||
return vscode.commands.executeCommand<T>(command, ...rest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration for a extensionName; NOT YET IMPLEMENTED
|
||||
* @param extensionName The string name of the extension to get the configuration for
|
||||
*/
|
||||
public getConfiguration(extensionName: string): vscode.WorkspaceConfiguration {
|
||||
return vscode.workspace.getConfiguration(extensionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 'true' if the active editor window has a .sql file, false otherwise
|
||||
*/
|
||||
public get isEditingSqlFile(): boolean {
|
||||
let sqlFile = false;
|
||||
let editor = this.activeTextEditor;
|
||||
if (editor) {
|
||||
if (editor.document.languageId === this._extensionConstants.languageId) {
|
||||
sqlFile = true;
|
||||
}
|
||||
}
|
||||
return sqlFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is emitted when a [text document](#TextDocument) is disposed.
|
||||
*/
|
||||
public get onDidCloseTextDocument(): vscode.Event<vscode.TextDocument> {
|
||||
return vscode.workspace.onDidCloseTextDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is emitted when a [text document](#TextDocument) is opened.
|
||||
*/
|
||||
public get onDidOpenTextDocument(): vscode.Event<vscode.TextDocument> {
|
||||
return vscode.workspace.onDidOpenTextDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is emitted when a [text document](#TextDocument) is saved to disk.
|
||||
*/
|
||||
public get onDidSaveTextDocument(): vscode.Event<vscode.TextDocument> {
|
||||
return vscode.workspace.onDidSaveTextDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the denoted document from disk. Will return early if the
|
||||
* document is already open, otherwise the document is loaded and the
|
||||
* [open document](#workspace.onDidOpenTextDocument)-event fires.
|
||||
* The document to open is denoted by the [uri](#Uri). Two schemes are supported:
|
||||
*
|
||||
* file: A file on disk, will be rejected if the file does not exist or cannot be loaded, e.g. `file:///Users/frodo/r.ini`.
|
||||
* untitled: A new file that should be saved on disk, e.g. `untitled:c:\frodo\new.js`. The language will be derived from the file name.
|
||||
*
|
||||
* Uris with other schemes will make this method return a rejected promise.
|
||||
*
|
||||
* @param uri Identifies the resource to open.
|
||||
* @return A promise that resolves to a [document](#TextDocument).
|
||||
* @see vscode.workspace.openTextDocument
|
||||
*/
|
||||
public openTextDocument(uri: vscode.Uri): Thenable<vscode.TextDocument> {
|
||||
return vscode.workspace.openTextDocument(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to log messages to output channel.
|
||||
*/
|
||||
public logToOutputChannel(msg: any): void {
|
||||
let date: Date = new Date();
|
||||
if (msg instanceof Array) {
|
||||
msg.forEach(element => {
|
||||
VscodeWrapper._outputChannel.appendLine('[' + date.toLocaleTimeString() + '] ' + element.toString());
|
||||
});
|
||||
} else {
|
||||
VscodeWrapper._outputChannel.appendLine('[' + date.toLocaleTimeString() + '] ' + msg.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vscode.Range object
|
||||
* @param start The start position for the range
|
||||
* @param end The end position for the range
|
||||
*/
|
||||
public range(start: vscode.Position, end: vscode.Position): vscode.Range {
|
||||
return new vscode.Range(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vscode.Position object
|
||||
* @param line The line for the position
|
||||
* @param column The column for the position
|
||||
*/
|
||||
public position(line: number, column: number): vscode.Position {
|
||||
return new vscode.Position(line, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vscode.Selection object
|
||||
* @param start The start postion of the selection
|
||||
* @param end The end position of the selection
|
||||
*/
|
||||
public selection(start: vscode.Position, end: vscode.Position): vscode.Selection {
|
||||
return new vscode.Selection(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and shows a vscode error message
|
||||
*/
|
||||
public showErrorMessage(msg: string, ...items: string[]): Thenable<string> {
|
||||
return vscode.window.showErrorMessage(this._extensionConstants.extensionName + ': ' + msg, ...items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and shows a vscode information message
|
||||
*/
|
||||
public showInformationMessage(msg: string, ...items: string[]): Thenable<string> {
|
||||
return vscode.window.showInformationMessage(this._extensionConstants.extensionName + ': ' + msg, ...items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a selection list.
|
||||
*
|
||||
* @param items An array of items, or a promise that resolves to an array of items.
|
||||
* @param options Configures the behavior of the selection list.
|
||||
* @return A promise that resolves to the selected item or undefined.
|
||||
*/
|
||||
public showQuickPick<T extends vscode.QuickPickItem>(items: T[] | Thenable<T[]>, options?: vscode.QuickPickOptions): Thenable<T> {
|
||||
return vscode.window.showQuickPick<T>(items, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the given document in a text editor. A [column](#ViewColumn) can be provided
|
||||
* to control where the editor is being shown. Might change the [active editor](#window.activeTextEditor).
|
||||
*
|
||||
* @param document A text document to be shown.
|
||||
* @param column A view column in which the editor should be shown. The default is the [one](#ViewColumn.One), other values
|
||||
* are adjusted to be __Min(column, columnCount + 1)__.
|
||||
* @param preserveFocus When `true` the editor will not take focus.
|
||||
* @return A promise that resolves to an [editor](#TextEditor).
|
||||
*/
|
||||
public showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
|
||||
return vscode.window.showTextDocument(document, column, preserveFocus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and shows a vscode warning message
|
||||
*/
|
||||
public showWarningMessage(msg: string): Thenable<string> {
|
||||
return vscode.window.showWarningMessage(this._extensionConstants.extensionName + ': ' + msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a array of the text editors currently visible in the window
|
||||
*/
|
||||
public get visibleEditors(): vscode.TextEditor[] {
|
||||
return vscode.window.visibleTextEditors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an URI from a file system path. The [scheme](#Uri.scheme)
|
||||
* will be `file`.
|
||||
*
|
||||
* @param path A file system or UNC path.
|
||||
* @return A new Uri instance.
|
||||
* @see vscode.Uri.file
|
||||
*/
|
||||
public uriFile(path: string): vscode.Uri {
|
||||
return vscode.Uri.file(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an URI from a string. Will throw if the given value is not
|
||||
* valid.
|
||||
*
|
||||
* @param value The string value of an Uri.
|
||||
* @return A new Uri instance.
|
||||
* @see vscode.Uri.parse
|
||||
*/
|
||||
public uriParse(value: string): vscode.Uri {
|
||||
return vscode.Uri.parse(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The folder that is open in VS Code. `undefined` when no folder
|
||||
* has been opened.
|
||||
*
|
||||
* @readonly
|
||||
* @see vscode.workspace.rootPath
|
||||
*/
|
||||
public get workspaceRootPath(): string {
|
||||
return vscode.workspace.rootPath;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { IDecompressProvider, IPackage } from './interfaces';
|
||||
import { ILogger } from '../models/interfaces';
|
||||
const decompress = require('decompress');
|
||||
|
||||
export default class DecompressProvider implements IDecompressProvider {
|
||||
public decompress(pkg: IPackage, logger: ILogger): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
decompress(pkg.tmpFile.name, pkg.installPath).then(files => {
|
||||
logger.appendLine(`Done! ${files.length} files unpacked.\n`);
|
||||
resolve();
|
||||
}).catch(decompressErr => {
|
||||
logger.appendLine(`[ERROR] ${decompressErr}`);
|
||||
reject(decompressErr);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
import { IPackage, IStatusView, PackageError, IHttpClient } from './interfaces';
|
||||
import { ILogger } from '../models/interfaces';
|
||||
import { parse as parseUrl, Url } from 'url';
|
||||
import * as https from 'https';
|
||||
import * as http from 'http';
|
||||
import { getProxyAgent } from './proxy';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
/*
|
||||
* Http client class to handle downloading files using http or https urls
|
||||
*/
|
||||
export default class HttpClient implements IHttpClient {
|
||||
|
||||
/*
|
||||
* Downloads a file and stores the result in the temp file inside the package object
|
||||
*/
|
||||
public downloadFile(urlString: string, pkg: IPackage, logger: ILogger, statusView: IStatusView, proxy?: string, strictSSL?: boolean): Promise<void> {
|
||||
const url = parseUrl(urlString);
|
||||
let options = this.getHttpClientOptions(url, proxy, strictSSL);
|
||||
let clientRequest = url.protocol === 'http:' ? http.request : https.request;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (!pkg.tmpFile || pkg.tmpFile.fd === 0) {
|
||||
return reject(new PackageError('Temporary package file unavailable', pkg));
|
||||
}
|
||||
|
||||
let request = clientRequest(options, response => {
|
||||
if (response.statusCode === 301 || response.statusCode === 302) {
|
||||
// Redirect - download from new location
|
||||
return resolve(this.downloadFile(response.headers.location, pkg, logger, statusView, proxy, strictSSL));
|
||||
}
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
// Download failed - print error message
|
||||
logger.appendLine(`failed (error code '${response.statusCode}')`);
|
||||
return reject(new PackageError(response.statusCode.toString(), pkg));
|
||||
}
|
||||
|
||||
// If status code is 200
|
||||
this.handleSuccessfulResponse(pkg, response, logger, statusView).then(_ => {
|
||||
resolve();
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
||||
request.on('error', error => {
|
||||
// reject(new PackageError(`Request error: ${error.code || 'NONE'}`, pkg, error));
|
||||
reject(new PackageError(`Request error: ${error.name || 'NONE'}`, pkg, error));
|
||||
});
|
||||
|
||||
// Execute the request
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
|
||||
private getHttpClientOptions(url: Url, proxy?: string, strictSSL?: boolean): any {
|
||||
const agent = getProxyAgent(url, proxy, strictSSL);
|
||||
|
||||
let options: http.RequestOptions = {
|
||||
host: url.hostname,
|
||||
path: url.path,
|
||||
agent: agent,
|
||||
port: +url.port
|
||||
};
|
||||
|
||||
if (url.protocol === 'https:') {
|
||||
let httpsOptions: https.RequestOptions = {
|
||||
host: url.hostname,
|
||||
path: url.path,
|
||||
agent: agent,
|
||||
port: +url.port
|
||||
};
|
||||
options = httpsOptions;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the download percentage and stores in the progress object
|
||||
*/
|
||||
public handleDataReceivedEvent(progress: IDownloadProgress, data: any, logger: ILogger, statusView: IStatusView): void {
|
||||
progress.downloadedBytes += data.length;
|
||||
|
||||
// Update status bar item with percentage
|
||||
if (progress.packageSize > 0) {
|
||||
let newPercentage = Math.ceil(100 * (progress.downloadedBytes / progress.packageSize));
|
||||
if (newPercentage !== progress.downloadPercentage) {
|
||||
statusView.updateServiceDownloadingProgress(progress.downloadPercentage);
|
||||
progress.downloadPercentage = newPercentage;
|
||||
}
|
||||
|
||||
// Update dots after package name in output console
|
||||
let newDots = Math.ceil(progress.downloadPercentage / 5);
|
||||
if (newDots > progress.dots) {
|
||||
logger.append('.'.repeat(newDots - progress.dots));
|
||||
progress.dots = newDots;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private handleSuccessfulResponse(pkg: IPackage, response: http.IncomingMessage, logger: ILogger, statusView: IStatusView): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let progress: IDownloadProgress = {
|
||||
packageSize: parseInt(response.headers['content-length'], 10),
|
||||
dots: 0,
|
||||
downloadedBytes: 0,
|
||||
downloadPercentage: 0
|
||||
};
|
||||
logger.append(`(${Math.ceil(progress.packageSize / 1024)} KB) `);
|
||||
response.on('data', data => {
|
||||
this.handleDataReceivedEvent(progress, data, logger, statusView);
|
||||
});
|
||||
let tmpFile = fs.createWriteStream(undefined, { fd: pkg.tmpFile.fd });
|
||||
response.on('end', () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
response.on('error', err => {
|
||||
reject(new PackageError(`Response error: ${err.name || 'NONE'}`, pkg, err));
|
||||
});
|
||||
|
||||
// Begin piping data from the response to the package file
|
||||
response.pipe(tmpFile, { end: false });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to store the values needed to calculate download percentage
|
||||
*/
|
||||
export interface IDownloadProgress {
|
||||
packageSize: number;
|
||||
downloadedBytes: number;
|
||||
downloadPercentage: number;
|
||||
dots: number;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as tmp from 'tmp';
|
||||
import { ILogger } from '../models/interfaces';
|
||||
|
||||
export interface IStatusView {
|
||||
installingService(): void;
|
||||
serviceInstalled(): void;
|
||||
serviceInstallationFailed(): void;
|
||||
updateServiceDownloadingProgress(downloadPercentage: number): void;
|
||||
}
|
||||
|
||||
export interface IConfig {
|
||||
getDownloadUrl(): string;
|
||||
getInstallDirectory(): string;
|
||||
getExecutableFiles(): string[];
|
||||
getPackageVersion(): string;
|
||||
getExtensionConfig(key: string, defaultValue?: any): any;
|
||||
getWorkspaceConfig(key: string, defaultValue?: any): any;
|
||||
getConfigValue(configKey: string): any;
|
||||
}
|
||||
|
||||
export interface IPackage {
|
||||
url: string;
|
||||
installPath?: string;
|
||||
tmpFile: tmp.SynchronousResult;
|
||||
}
|
||||
|
||||
export class PackageError extends Error {
|
||||
// Do not put PII (personally identifiable information) in the 'message' field as it will be logged to telemetry
|
||||
constructor(public message: string,
|
||||
public pkg: IPackage = undefined,
|
||||
public innerError: any = undefined) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IHttpClient {
|
||||
downloadFile(urlString: string, pkg: IPackage, logger: ILogger, statusView: IStatusView, proxy: string, strictSSL: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IDecompressProvider {
|
||||
decompress(pkg: IPackage, logger: ILogger): Promise<void>;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Url, parse as parseUrl } from 'url';
|
||||
const HttpProxyAgent = require('http-proxy-agent');
|
||||
const HttpsProxyAgent = require('https-proxy-agent');
|
||||
|
||||
function getSystemProxyURL(requestURL: Url): string {
|
||||
if (requestURL.protocol === 'http:') {
|
||||
return process.env.HTTP_PROXY || process.env.http_proxy || undefined;
|
||||
} else if (requestURL.protocol === 'https:') {
|
||||
return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the proxy agent using the proxy url in the parameters or the system proxy. Returns null if no proxy found
|
||||
*/
|
||||
export function getProxyAgent(requestURL: Url, proxy?: string, strictSSL?: boolean): any {
|
||||
const proxyURL = proxy || getSystemProxyURL(requestURL);
|
||||
|
||||
if (!proxyURL) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const proxyEndpoint = parseUrl(proxyURL);
|
||||
|
||||
if (!/^https?:$/.test(proxyEndpoint.protocol)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
strictSSL = strictSSL || true;
|
||||
|
||||
const opts = {
|
||||
host: proxyEndpoint.hostname,
|
||||
port: Number(proxyEndpoint.port),
|
||||
auth: proxyEndpoint.auth,
|
||||
rejectUnauthorized: strictSSL
|
||||
};
|
||||
|
||||
return requestURL.protocol === 'http:' ? new HttpProxyAgent(opts) : new HttpsProxyAgent(opts);
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import { Runtime } from '../models/platform';
|
||||
import ServiceDownloadProvider from './serviceDownloadProvider';
|
||||
import { IConfig, IStatusView } from './interfaces';
|
||||
const fs = require('fs-extra-promise');
|
||||
|
||||
|
||||
/*
|
||||
* Service Provider class finds the SQL tools service executable file or downloads it if doesn't exist.
|
||||
*/
|
||||
export default class ServerProvider {
|
||||
|
||||
constructor(private _downloadProvider: ServiceDownloadProvider,
|
||||
private _config: IConfig,
|
||||
private _statusView: IStatusView,
|
||||
private _extensionConfigSectionName: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Public get method for downloadProvider
|
||||
*/
|
||||
public get downloadProvider(): ServiceDownloadProvider {
|
||||
return this._downloadProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a file path, returns the path to the SQL Tools service file.
|
||||
*/
|
||||
public findServerPath(filePath: string, executableFiles: string[] = undefined): Promise<string> {
|
||||
return fs.lstatAsync(filePath).then(stats => {
|
||||
// If a file path was passed, assume its the launch file.
|
||||
if (stats.isFile()) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
// Otherwise, search the specified folder.
|
||||
let candidate: string;
|
||||
|
||||
if (executableFiles === undefined && this._config !== undefined) {
|
||||
executableFiles = this._config.getExecutableFiles();
|
||||
}
|
||||
if (executableFiles !== undefined) {
|
||||
executableFiles.forEach(element => {
|
||||
let executableFile = path.join(filePath, element);
|
||||
if (candidate === undefined && fs.existsSync(executableFile)) {
|
||||
candidate = executableFile;
|
||||
return candidate;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return candidate;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the service if doesn't exist and returns the file path.
|
||||
*/
|
||||
public getOrDownloadServer(runtime: Runtime): Promise<string> {
|
||||
// Attempt to find launch file path first from options, and then from the default install location.
|
||||
// If SQL tools service can't be found, download it.
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
return this.getServerPath(runtime).then(result => {
|
||||
if (result === undefined) {
|
||||
return this.downloadServerFiles(runtime).then ( downloadResult => {
|
||||
resolve(downloadResult);
|
||||
});
|
||||
} else {
|
||||
return resolve(result);
|
||||
}
|
||||
}).catch(err => {
|
||||
return reject(err);
|
||||
});
|
||||
}).catch(err => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the installed service
|
||||
*/
|
||||
public getServerPath(runtime: Runtime): Promise<string> {
|
||||
const installDirectory = this._downloadProvider.getInstallDirectory(runtime, this._extensionConfigSectionName);
|
||||
return this.findServerPath(installDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the service and returns the path of the installed service
|
||||
*/
|
||||
public downloadServerFiles(runtime: Runtime): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const installDirectory = this._downloadProvider.getInstallDirectory(runtime, this._extensionConfigSectionName);
|
||||
return this._downloadProvider.installService(runtime).then( _ => {
|
||||
return this.findServerPath(installDirectory).then ( result => {
|
||||
return resolve(result);
|
||||
});
|
||||
}).catch(err => {
|
||||
this._statusView.serviceInstallationFailed();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { IStatusView } from './interfaces';
|
||||
import vscode = require('vscode');
|
||||
import { IExtensionConstants } from '../models/contracts/contracts';
|
||||
import { Constants } from '../models/constants';
|
||||
|
||||
/*
|
||||
* The status class which includes the service initialization result.
|
||||
*/
|
||||
export class ServerInitializationResult {
|
||||
|
||||
public constructor(
|
||||
public installedBeforeInitializing: Boolean = false,
|
||||
public isRunning: Boolean = false,
|
||||
public serverPath: string = undefined
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public Clone(): ServerInitializationResult {
|
||||
return new ServerInitializationResult(this.installedBeforeInitializing, this.isRunning, this.serverPath);
|
||||
}
|
||||
|
||||
public WithRunning(isRunning: Boolean): ServerInitializationResult {
|
||||
return new ServerInitializationResult(this.installedBeforeInitializing, isRunning, this.serverPath);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The status class shows service installing progress in UI
|
||||
*/
|
||||
export class ServerStatusView implements IStatusView, vscode.Disposable {
|
||||
private _numberOfSecondsBeforeHidingMessage = 5000;
|
||||
private _statusBarItem: vscode.StatusBarItem = undefined;
|
||||
private _progressTimerId: NodeJS.Timer;
|
||||
private _constants: IExtensionConstants;
|
||||
|
||||
constructor(constants: IExtensionConstants) {
|
||||
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
vscode.window.onDidChangeActiveTextEditor((params) => this.onDidChangeActiveTextEditor(params));
|
||||
vscode.workspace.onDidCloseTextDocument((params) => this.onDidCloseTextDocument(params));
|
||||
this._constants = constants;
|
||||
}
|
||||
|
||||
public installingService(): void {
|
||||
this._statusBarItem.command = undefined;
|
||||
this._statusBarItem.show();
|
||||
|
||||
this.showProgress('$(desktop-download) ' + Constants.serviceInstalling);
|
||||
}
|
||||
|
||||
public updateServiceDownloadingProgress(downloadPercentage: number): void {
|
||||
this._statusBarItem.text = '$(cloud-download) ' + `${Constants.serviceDownloading} ... ${downloadPercentage}%`;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
|
||||
public serviceInstalled(): void {
|
||||
|
||||
this._statusBarItem.command = undefined;
|
||||
this._statusBarItem.text = this._constants.serviceInstalled;
|
||||
this._statusBarItem.show();
|
||||
// Cleat the status bar after 2 seconds
|
||||
setTimeout(() => {
|
||||
this._statusBarItem.hide();
|
||||
}, this._numberOfSecondsBeforeHidingMessage);
|
||||
}
|
||||
|
||||
public serviceInstallationFailed(): void {
|
||||
this._statusBarItem.command = undefined;
|
||||
this._statusBarItem.text = this._constants.serviceInstallationFailed;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
|
||||
private showProgress(statusText: string): void {
|
||||
let index = 0;
|
||||
let progressTicks = [ '|', '/', '-', '\\'];
|
||||
|
||||
|
||||
this._progressTimerId = setInterval(() => {
|
||||
index++;
|
||||
if (index > 3) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
let progressTick = progressTicks[index];
|
||||
if (this._statusBarItem.text !== this._constants.serviceInstalled) {
|
||||
this._statusBarItem.text = statusText + ' ' + progressTick;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.destroyStatusBar();
|
||||
}
|
||||
|
||||
private hideLastShownStatusBar(): void {
|
||||
if (typeof this._statusBarItem !== 'undefined') {
|
||||
this._statusBarItem.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
|
||||
// Hide the most recently shown status bar
|
||||
this.hideLastShownStatusBar();
|
||||
}
|
||||
|
||||
private onDidCloseTextDocument(doc: vscode.TextDocument): void {
|
||||
// Remove the status bar associated with the document
|
||||
this.destroyStatusBar();
|
||||
}
|
||||
|
||||
private destroyStatusBar(): void {
|
||||
if (typeof this._statusBarItem !== 'undefined') {
|
||||
this._statusBarItem.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,535 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { ExtensionContext, workspace, window, OutputChannel, languages } from 'vscode';
|
||||
import * as SqlopsClient from 'dataprotocol-client';
|
||||
import { CloseAction, ErrorAction, ServerOptions, NotificationHandler, NotificationType, RequestType, TransportKind } from 'vscode-languageclient';
|
||||
|
||||
import { VscodeWrapper } from '../controllers/vscodeWrapper';
|
||||
import { Telemetry } from '../models/telemetry';
|
||||
import { Utils } from '../models/utils';
|
||||
import { VersionRequest, IExtensionConstants } from '../models/contracts/contracts';
|
||||
import { Logger } from '../models/logger';
|
||||
import ServerProvider from './server';
|
||||
import ServiceDownloadProvider from './serviceDownloadProvider';
|
||||
import DecompressProvider from './decompressProvider';
|
||||
import HttpClient from './httpClient';
|
||||
import ExtConfig from '../configurations/extConfig';
|
||||
import { PlatformInformation, Runtime } from '../models/platform';
|
||||
import { ServerInitializationResult, ServerStatusView } from './serverStatus';
|
||||
import StatusView from '../views/statusView';
|
||||
import * as LanguageServiceContracts from '../models/contracts/languageService';
|
||||
import { Constants } from '../models/constants';
|
||||
import ServiceStatus from './serviceStatus';
|
||||
|
||||
const opener = require('opener');
|
||||
const path = require('path');
|
||||
let _channel: OutputChannel = undefined;
|
||||
|
||||
/**
|
||||
* @interface IMessage
|
||||
*/
|
||||
interface IMessage {
|
||||
jsonrpc: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Language Service client errors
|
||||
* @class LanguageClientErrorHandler
|
||||
*/
|
||||
class LanguageClientErrorHandler {
|
||||
|
||||
private vscodeWrapper: VscodeWrapper;
|
||||
|
||||
/**
|
||||
* Creates an instance of LanguageClientErrorHandler.
|
||||
* @memberOf LanguageClientErrorHandler
|
||||
*/
|
||||
constructor(constants: IExtensionConstants) {
|
||||
if (!this.vscodeWrapper) {
|
||||
this.vscodeWrapper = new VscodeWrapper(constants);
|
||||
}
|
||||
Telemetry.getRuntimeId = this.vscodeWrapper.constants.getRuntimeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an error message prompt with a link to known issues wiki page
|
||||
* @memberOf LanguageClientErrorHandler
|
||||
*/
|
||||
showOnErrorPrompt(): void {
|
||||
let extensionConstants = this.vscodeWrapper.constants;
|
||||
Telemetry.sendTelemetryEvent(extensionConstants.serviceName + 'Crash');
|
||||
this.vscodeWrapper.showErrorMessage(
|
||||
extensionConstants.serviceCrashMessage,
|
||||
Constants.serviceCrashButton).then(action => {
|
||||
if (action && action === Constants.serviceCrashButton) {
|
||||
opener(extensionConstants.serviceCrashLink);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for language service client error
|
||||
*
|
||||
* @param {Error} error
|
||||
* @param {Message} message
|
||||
* @param {number} count
|
||||
* @returns {ErrorAction}
|
||||
*
|
||||
* @memberOf LanguageClientErrorHandler
|
||||
*/
|
||||
error(error: Error, message: IMessage, count: number): ErrorAction {
|
||||
this.showOnErrorPrompt();
|
||||
|
||||
// we don't retry running the service since crashes leave the extension
|
||||
// in a bad, unrecovered state
|
||||
return ErrorAction.Shutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for language service client closed
|
||||
*
|
||||
* @returns {CloseAction}
|
||||
*
|
||||
* @memberOf LanguageClientErrorHandler
|
||||
*/
|
||||
closed(): CloseAction {
|
||||
this.showOnErrorPrompt();
|
||||
|
||||
// we don't retry running the service since crashes leave the extension
|
||||
// in a bad, unrecovered state
|
||||
return CloseAction.DoNotRestart;
|
||||
}
|
||||
}
|
||||
|
||||
// The Service Client class handles communication with the VS Code LanguageClient
|
||||
export class SqlToolsServiceClient {
|
||||
// singleton instance
|
||||
private static _instance: SqlToolsServiceClient = undefined;
|
||||
|
||||
private static _constants: IExtensionConstants = undefined;
|
||||
|
||||
public static get constants(): IExtensionConstants {
|
||||
return this._constants;
|
||||
}
|
||||
|
||||
public static set constants(constantsObject: IExtensionConstants) {
|
||||
this._constants = constantsObject;
|
||||
Telemetry.getRuntimeId = this._constants.getRuntimeId;
|
||||
}
|
||||
|
||||
private static _helper: LanguageServiceContracts.ILanguageClientHelper = undefined;
|
||||
|
||||
public static get helper(): LanguageServiceContracts.ILanguageClientHelper {
|
||||
return this._helper;
|
||||
}
|
||||
|
||||
public static set helper(helperObject: LanguageServiceContracts.ILanguageClientHelper) {
|
||||
this._helper = helperObject;
|
||||
}
|
||||
|
||||
// VS Code Language Client
|
||||
private _client: SqlopsClient.SqlOpsDataClient = undefined;
|
||||
|
||||
// getter method for the Language Client
|
||||
private get client(): SqlopsClient.SqlOpsDataClient {
|
||||
return this._client;
|
||||
}
|
||||
|
||||
private set client(client: SqlopsClient.SqlOpsDataClient) {
|
||||
this._client = client;
|
||||
}
|
||||
|
||||
public installDirectory: string;
|
||||
private _downloadProvider: ServiceDownloadProvider;
|
||||
private _vscodeWrapper: VscodeWrapper;
|
||||
|
||||
private _serviceStatus: ServiceStatus;
|
||||
|
||||
private _languageClientStartTime: number = undefined;
|
||||
private _installationTime: number = undefined;
|
||||
|
||||
constructor(
|
||||
private _server: ServerProvider,
|
||||
private _logger: Logger,
|
||||
private _statusView: StatusView,
|
||||
private _config: ExtConfig) {
|
||||
this._downloadProvider = _server.downloadProvider;
|
||||
if (!this._vscodeWrapper) {
|
||||
this._vscodeWrapper = new VscodeWrapper(SqlToolsServiceClient.constants);
|
||||
}
|
||||
this._serviceStatus = new ServiceStatus(SqlToolsServiceClient._constants.serviceName);
|
||||
}
|
||||
|
||||
// gets or creates the singleton service client instance
|
||||
public static getInstance(path: string): SqlToolsServiceClient {
|
||||
if (this._instance === undefined) {
|
||||
let constants = this._constants;
|
||||
let config = new ExtConfig(constants.extensionConfigSectionName, undefined, path);
|
||||
_channel = window.createOutputChannel(constants.serviceInitializingOutputChannelName);
|
||||
let logger = new Logger(text => _channel.append(text), constants);
|
||||
let serverStatusView = new ServerStatusView(constants);
|
||||
let httpClient = new HttpClient();
|
||||
let decompressProvider = new DecompressProvider();
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger, serverStatusView, httpClient,
|
||||
decompressProvider, constants, false);
|
||||
let serviceProvider = new ServerProvider(downloadProvider, config, serverStatusView, constants.extensionConfigSectionName);
|
||||
let statusView = new StatusView();
|
||||
this._instance = new SqlToolsServiceClient(serviceProvider, logger, statusView, config);
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
// initialize the Service Client instance by launching
|
||||
// out-of-proc server through the LanguageClient
|
||||
public initialize(context: ExtensionContext): Promise<any> {
|
||||
this._logger.appendLine(SqlToolsServiceClient._constants.serviceInitializing);
|
||||
this._languageClientStartTime = Date.now();
|
||||
return PlatformInformation.getCurrent(SqlToolsServiceClient._constants.getRuntimeId, SqlToolsServiceClient._constants.extensionName).then(platformInfo => {
|
||||
return this.initializeForPlatform(platformInfo, context);
|
||||
}).catch(err => {
|
||||
this._vscodeWrapper.showErrorMessage(err);
|
||||
});
|
||||
}
|
||||
|
||||
public initializeForPlatform(platformInfo: PlatformInformation, context: ExtensionContext): Promise<ServerInitializationResult> {
|
||||
return new Promise<ServerInitializationResult>((resolve, reject) => {
|
||||
this._logger.appendLine(SqlToolsServiceClient._constants.commandsNotAvailableWhileInstallingTheService);
|
||||
this._logger.appendLine();
|
||||
this._logger.append(`Platform: ${platformInfo.toString()}`);
|
||||
|
||||
if (!platformInfo.isValidRuntime()) {
|
||||
// if it's an unknown Linux distro then try generic Linux x64 and give a warning to the user
|
||||
if (platformInfo.isLinux()) {
|
||||
this._logger.appendLine(Constants.usingDefaultPlatformMessage);
|
||||
platformInfo.runtimeId = Runtime.Linux_64;
|
||||
}
|
||||
|
||||
let ignoreWarning: boolean = this._config.getWorkspaceConfig(Constants.ignorePlatformWarning, false);
|
||||
if (!ignoreWarning) {
|
||||
this._vscodeWrapper.showErrorMessage(
|
||||
Constants.unsupportedPlatformErrorMessage,
|
||||
Constants.neverShowAgain)
|
||||
.then(action => {
|
||||
if (action === Constants.neverShowAgain) {
|
||||
this._config.updateWorkspaceConfig(Constants.ignorePlatformWarning, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Telemetry.sendTelemetryEvent('UnsupportedPlatform', { platform: platformInfo.toString() });
|
||||
}
|
||||
|
||||
if (platformInfo.runtimeId) {
|
||||
this._logger.appendLine(` (${platformInfo.getRuntimeDisplayName()})`);
|
||||
} else {
|
||||
this._logger.appendLine();
|
||||
}
|
||||
|
||||
this._logger.appendLine();
|
||||
|
||||
this._server.getServerPath(platformInfo.runtimeId).then(serverPath => {
|
||||
if (serverPath === undefined) {
|
||||
// Check if the service already installed and if not open the output channel to show the logs
|
||||
if (_channel !== undefined) {
|
||||
_channel.show();
|
||||
}
|
||||
let installationStartTime = Date.now();
|
||||
this._server.downloadServerFiles(platformInfo.runtimeId).then(installedServerPath => {
|
||||
this._installationTime = Date.now() - installationStartTime;
|
||||
this.initializeLanguageClient(installedServerPath, context, platformInfo.runtimeId);
|
||||
resolve(new ServerInitializationResult(true, true, installedServerPath));
|
||||
}).catch(downloadErr => {
|
||||
reject(downloadErr);
|
||||
});
|
||||
} else {
|
||||
this.initializeLanguageClient(serverPath, context, platformInfo.runtimeId);
|
||||
resolve(new ServerInitializationResult(false, true, serverPath));
|
||||
}
|
||||
}).catch(err => {
|
||||
Utils.logDebug(SqlToolsServiceClient._constants.serviceLoadingFailed + ' ' + err, SqlToolsServiceClient._constants.extensionConfigSectionName);
|
||||
Utils.showErrorMsg(SqlToolsServiceClient._constants.serviceLoadingFailed, SqlToolsServiceClient._constants.extensionName);
|
||||
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SQL language configuration
|
||||
*
|
||||
* @memberOf SqlToolsServiceClient
|
||||
*/
|
||||
private initializeLanguageConfiguration(): void {
|
||||
languages.setLanguageConfiguration('sql', {
|
||||
comments: {
|
||||
lineComment: '--',
|
||||
blockComment: ['/*', '*/']
|
||||
},
|
||||
|
||||
brackets: [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')']
|
||||
],
|
||||
|
||||
__characterPairSupport: {
|
||||
autoClosingPairs: [
|
||||
{ open: '{', close: '}' },
|
||||
{ open: '[', close: ']' },
|
||||
{ open: '(', close: ')' },
|
||||
{ open: '"', close: '"', notIn: ['string'] },
|
||||
{ open: '\'', close: '\'', notIn: ['string', 'comment'] }
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initializeLanguageClient(serverPath: string, context: ExtensionContext, runtimeId: Runtime): void {
|
||||
if (serverPath === undefined) {
|
||||
Utils.logDebug(SqlToolsServiceClient._constants.invalidServiceFilePath, SqlToolsServiceClient._constants.extensionConfigSectionName);
|
||||
throw new Error(SqlToolsServiceClient._constants.invalidServiceFilePath);
|
||||
} else {
|
||||
let self = this;
|
||||
|
||||
if (SqlToolsServiceClient._constants.languageId === 'sql') {
|
||||
self.initializeLanguageConfiguration();
|
||||
}
|
||||
|
||||
// Use default createServerOptions if one isn't specified
|
||||
let serverOptions: ServerOptions = SqlToolsServiceClient._helper ?
|
||||
SqlToolsServiceClient._helper.createServerOptions(serverPath, runtimeId) : self.createServerOptions(serverPath);
|
||||
this.client = this.createLanguageClient(serverOptions);
|
||||
this.installDirectory = this._downloadProvider.getInstallDirectory(runtimeId, SqlToolsServiceClient._constants.extensionConfigSectionName);
|
||||
|
||||
if (context !== undefined) {
|
||||
// Create the language client and start the client.
|
||||
let disposable = this.client.start();
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public createClient(context: ExtensionContext, runtimeId: Runtime, languageClientHelper: LanguageServiceContracts.ILanguageClientHelper, executableFiles: string[]): Promise<SqlopsClient.SqlOpsDataClient> {
|
||||
return new Promise<SqlopsClient.SqlOpsDataClient>((resolve, reject) => {
|
||||
let client: SqlopsClient.SqlOpsDataClient;
|
||||
this._server.findServerPath(this.installDirectory, executableFiles).then(serverPath => {
|
||||
if (serverPath === undefined) {
|
||||
reject(new Error(SqlToolsServiceClient._constants.invalidServiceFilePath));
|
||||
} else {
|
||||
|
||||
let serverOptions: ServerOptions = languageClientHelper ?
|
||||
languageClientHelper.createServerOptions(serverPath, runtimeId) : this.createServerOptions(serverPath);
|
||||
|
||||
// Options to control the language client
|
||||
let clientOptions: SqlopsClient.ClientOptions = {
|
||||
documentSelector: [SqlToolsServiceClient._constants.languageId],
|
||||
providerId: '',
|
||||
synchronize: {
|
||||
configurationSection: SqlToolsServiceClient._constants.extensionConfigSectionName
|
||||
},
|
||||
errorHandler: new LanguageClientErrorHandler(SqlToolsServiceClient._constants),
|
||||
outputChannel: {
|
||||
append: () => {
|
||||
},
|
||||
appendLine: () => {
|
||||
},
|
||||
dispose: () => {
|
||||
},
|
||||
clear: () => {
|
||||
},
|
||||
hide: () => {
|
||||
},
|
||||
name: '',
|
||||
show: () => {
|
||||
}
|
||||
},
|
||||
// pass in no features so we don't register features we don't want
|
||||
features: []
|
||||
};
|
||||
|
||||
this._serviceStatus.showServiceLoading();
|
||||
// cache the client instance for later use
|
||||
client = new SqlopsClient.SqlOpsDataClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions);
|
||||
|
||||
if (context !== undefined) {
|
||||
// Create the language client and start the client.
|
||||
let disposable = client.start();
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
client.onReady().then(this._serviceStatus.showServiceLoaded);
|
||||
|
||||
resolve(client);
|
||||
}
|
||||
}, error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private createServerOptions(servicePath): ServerOptions {
|
||||
let serverArgs = [];
|
||||
let serverCommand: string = servicePath;
|
||||
if (servicePath.endsWith('.dll')) {
|
||||
serverArgs = [servicePath];
|
||||
serverCommand = 'dotnet';
|
||||
}
|
||||
|
||||
// Enable diagnostic logging in the service if it is configured
|
||||
let config = workspace.getConfiguration(SqlToolsServiceClient._constants.extensionConfigSectionName);
|
||||
if (config) {
|
||||
let logDebugInfo = config[Constants.configLogDebugInfo];
|
||||
if (logDebugInfo) {
|
||||
serverArgs.push('--enable-logging');
|
||||
}
|
||||
}
|
||||
serverArgs.push('--log-dir');
|
||||
let logFileLocation = path.join(Utils.getDefaultLogLocation(), SqlToolsServiceClient.constants.extensionName);
|
||||
serverArgs.push(logFileLocation);
|
||||
|
||||
// run the service host using dotnet.exe from the path
|
||||
let serverOptions: ServerOptions = { command: serverCommand, args: serverArgs, transport: TransportKind.stdio };
|
||||
return serverOptions;
|
||||
}
|
||||
|
||||
private createLanguageClient(serverOptions: ServerOptions): SqlopsClient.SqlOpsDataClient {
|
||||
// Options to control the language client
|
||||
let clientOptions: SqlopsClient.ClientOptions = {
|
||||
documentSelector: [SqlToolsServiceClient._constants.languageId],
|
||||
providerId: SqlToolsServiceClient._constants.providerId,
|
||||
synchronize: {
|
||||
configurationSection: SqlToolsServiceClient._constants.extensionConfigSectionName
|
||||
},
|
||||
errorHandler: new LanguageClientErrorHandler(SqlToolsServiceClient._constants),
|
||||
outputChannel: {
|
||||
append: () => {
|
||||
},
|
||||
appendLine: () => {
|
||||
},
|
||||
dispose: () => {
|
||||
},
|
||||
clear: () => {
|
||||
},
|
||||
hide: () => {
|
||||
},
|
||||
name: '',
|
||||
show: () => {
|
||||
}
|
||||
},
|
||||
features: [
|
||||
SqlopsClient.AdminServicesFeature,
|
||||
SqlopsClient.BackupFeature,
|
||||
SqlopsClient.CapabilitiesFeature,
|
||||
SqlopsClient.ConnectionFeature,
|
||||
SqlopsClient.FileBrowserFeature,
|
||||
SqlopsClient.MetadataFeature,
|
||||
SqlopsClient.ObjectExplorerFeature,
|
||||
SqlopsClient.ProfilerFeature,
|
||||
SqlopsClient.QueryFeature,
|
||||
SqlopsClient.RestoreFeature,
|
||||
SqlopsClient.ScriptingFeature,
|
||||
SqlopsClient.TaskServicesFeature,
|
||||
// heres the important bit
|
||||
LanguageServiceContracts.AgentServicesFeature
|
||||
]
|
||||
};
|
||||
|
||||
this._serviceStatus.showServiceLoading();
|
||||
// cache the client instance for later use
|
||||
let client = new SqlopsClient.SqlOpsDataClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions);
|
||||
client.onReady().then(() => {
|
||||
this.checkServiceCompatibility();
|
||||
this._serviceStatus.showServiceLoaded();
|
||||
client.onNotification(LanguageServiceContracts.TelemetryNotification.type, this.handleLanguageServiceTelemetryNotification());
|
||||
client.onNotification(LanguageServiceContracts.StatusChangedNotification.type, this.handleLanguageServiceStatusNotification());
|
||||
|
||||
// Report the language client startup time
|
||||
let endTime = Date.now();
|
||||
let installationTime = this._installationTime || 0;
|
||||
let totalTime = endTime - this._languageClientStartTime;
|
||||
let processStartupTime = totalTime - installationTime;
|
||||
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
|
||||
installationTime: String(installationTime),
|
||||
processStartupTime: String(processStartupTime),
|
||||
totalTime: String(totalTime),
|
||||
beginningTimestamp: String(this._languageClientStartTime)
|
||||
});
|
||||
this._languageClientStartTime = undefined;
|
||||
this._installationTime = undefined;
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private handleLanguageServiceTelemetryNotification(): NotificationHandler<LanguageServiceContracts.TelemetryParams> {
|
||||
return (event: LanguageServiceContracts.TelemetryParams): void => {
|
||||
Telemetry.sendTelemetryEvent(event.params.eventName, event.params.properties, event.params.measures);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Public for testing purposes only.
|
||||
*/
|
||||
public handleLanguageServiceStatusNotification(): NotificationHandler<LanguageServiceContracts.StatusChangeParams> {
|
||||
return (event: LanguageServiceContracts.StatusChangeParams): void => {
|
||||
this._statusView.languageServiceStatusChanged(event.ownerUri, event.status);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to the service client
|
||||
* @param type The of the request to make
|
||||
* @param params The params to pass with the request
|
||||
* @returns A thenable object for when the request receives a response
|
||||
*/
|
||||
public sendRequest<P, R, E, RO>(type: RequestType<P, R, E, RO>, params?: P, client: SqlopsClient.SqlOpsDataClient = undefined): Thenable<R> {
|
||||
if (client === undefined) {
|
||||
client = this._client;
|
||||
}
|
||||
if (client !== undefined) {
|
||||
return client.sendRequest(type, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler for a notification type
|
||||
* @param type The notification type to register the handler for
|
||||
* @param handler The handler to register
|
||||
*/
|
||||
public onNotification<P, RO>(type: NotificationType<P, RO>, handler: NotificationHandler<P>, client: SqlopsClient.SqlOpsDataClient = undefined): void {
|
||||
if (client === undefined) {
|
||||
client = this._client;
|
||||
}
|
||||
if (client !== undefined) {
|
||||
return client.onNotification(type, handler);
|
||||
}
|
||||
}
|
||||
|
||||
public checkServiceCompatibility(): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
this._client.sendRequest(VersionRequest.type, undefined).then((result) => {
|
||||
Utils.logDebug(SqlToolsServiceClient._constants.extensionName + ' service client version: ' + result, SqlToolsServiceClient._constants.extensionConfigSectionName);
|
||||
|
||||
if (result === undefined || !result.startsWith(SqlToolsServiceClient._constants.serviceCompatibleVersion)) {
|
||||
Utils.showErrorMsg(Constants.serviceNotCompatibleError, SqlToolsServiceClient._constants.extensionName);
|
||||
Utils.logDebug(Constants.serviceNotCompatibleError, SqlToolsServiceClient._constants.extensionConfigSectionName);
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Runtime, getRuntimeDisplayName } from '../models/platform';
|
||||
import * as path from 'path';
|
||||
import { IConfig, IStatusView, IPackage, PackageError, IHttpClient, IDecompressProvider } from './interfaces';
|
||||
import { ILogger } from '../models/interfaces';
|
||||
import { Constants } from '../models/constants';
|
||||
import * as tmp from 'tmp';
|
||||
import { IExtensionConstants } from '../models/contracts/contracts';
|
||||
|
||||
const fse = require('fs-extra');
|
||||
|
||||
/*
|
||||
* Service Download Provider class which handles downloading the SQL Tools service.
|
||||
*/
|
||||
export default class ServiceDownloadProvider {
|
||||
|
||||
constructor(private _config: IConfig,
|
||||
private _logger: ILogger,
|
||||
private _statusView: IStatusView,
|
||||
private _httpClient: IHttpClient,
|
||||
private _decompressProvider: IDecompressProvider,
|
||||
private _extensionConstants: IExtensionConstants,
|
||||
private _fromBuild: boolean) {
|
||||
// Ensure our temp files get cleaned up in case of error.
|
||||
tmp.setGracefulCleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the download url for given platform
|
||||
*/
|
||||
public getDownloadFileName(platform: Runtime): string {
|
||||
let fileNamesJson = this._config.getConfigValue('downloadFileNames');
|
||||
console.info('Platform: ', platform.toString());
|
||||
|
||||
let fileName = fileNamesJson[platform.toString()];
|
||||
console.info('Filename: ', fileName);
|
||||
|
||||
if (fileName === undefined) {
|
||||
if (process.platform === 'linux') {
|
||||
throw new Error('Unsupported linux distribution');
|
||||
} else {
|
||||
throw new Error(`Unsupported platform: ${process.platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns SQL tools service installed folder.
|
||||
*/
|
||||
public getInstallDirectory(platform: Runtime, extensionConfigSectionName: string): string {
|
||||
let basePath = this.getInstallDirectoryRoot(platform, extensionConfigSectionName);
|
||||
let versionFromConfig = this._config.getPackageVersion();
|
||||
basePath = basePath.replace('{#version#}', versionFromConfig);
|
||||
basePath = basePath.replace('{#platform#}', getRuntimeDisplayName(platform));
|
||||
if (!fse.existsSync(basePath)) {
|
||||
fse.mkdirsSync(basePath);
|
||||
}
|
||||
|
||||
return basePath;
|
||||
}
|
||||
|
||||
private getLocalUserFolderPath(platform: Runtime): string {
|
||||
if (platform) {
|
||||
switch (platform) {
|
||||
case Runtime.Windows_64:
|
||||
case Runtime.Windows_86:
|
||||
return process.env.APPDATA;
|
||||
case Runtime.OSX:
|
||||
return process.env.HOME + '/Library/Preferences';
|
||||
default:
|
||||
return process.env.HOME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SQL tools service installed folder root.
|
||||
*/
|
||||
public getInstallDirectoryRoot(platform: Runtime, extensionConfigSectionName: string): string {
|
||||
let installDirFromConfig : string;
|
||||
installDirFromConfig = this._config.getInstallDirectory();
|
||||
if (!installDirFromConfig || installDirFromConfig === '') {
|
||||
let rootFolderName: string = '.sqlops';
|
||||
if (platform === Runtime.Windows_64 || platform === Runtime.Windows_86) {
|
||||
rootFolderName = 'sqlops';
|
||||
}
|
||||
installDirFromConfig = path.join(this.getLocalUserFolderPath(platform), `/${rootFolderName}/${this._extensionConstants.installFolderName}/{#version#}/{#platform#}`);
|
||||
}
|
||||
let basePath: string;
|
||||
if (path.isAbsolute(installDirFromConfig)) {
|
||||
basePath = installDirFromConfig;
|
||||
} else if (this._fromBuild) {
|
||||
basePath = path.join(__dirname, '../../../extensions/' + extensionConfigSectionName + '/' + installDirFromConfig);
|
||||
} else {
|
||||
// The path from config is relative to the out folder
|
||||
basePath = path.join(__dirname, '../../../../' + installDirFromConfig);
|
||||
}
|
||||
return basePath;
|
||||
}
|
||||
|
||||
private getGetDownloadUrl(fileName: string): string {
|
||||
let baseDownloadUrl = this._config.getDownloadUrl();
|
||||
let version = this._config.getPackageVersion();
|
||||
baseDownloadUrl = baseDownloadUrl.replace('{#version#}', version);
|
||||
baseDownloadUrl = baseDownloadUrl.replace('{#fileName#}', fileName);
|
||||
return baseDownloadUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the service and decompress it in the install folder.
|
||||
*/
|
||||
public installService(platform: Runtime): Promise<boolean> {
|
||||
const proxy = <string>this._config.getWorkspaceConfig('http.proxy');
|
||||
const strictSSL = this._config.getWorkspaceConfig('http.proxyStrictSSL', true);
|
||||
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
const fileName = this.getDownloadFileName(platform);
|
||||
const installDirectory = this.getInstallDirectory(platform, this._extensionConstants.extensionConfigSectionName);
|
||||
|
||||
this._logger.appendLine(`${this._extensionConstants.serviceInstallingTo} ${installDirectory}.`);
|
||||
const urlString = this.getGetDownloadUrl(fileName);
|
||||
|
||||
this._logger.appendLine(`${Constants.serviceDownloading} ${urlString}`);
|
||||
let pkg: IPackage = {
|
||||
installPath: installDirectory,
|
||||
url: urlString,
|
||||
tmpFile: undefined
|
||||
};
|
||||
this.createTempFile(pkg).then(tmpResult => {
|
||||
pkg.tmpFile = tmpResult;
|
||||
|
||||
this._httpClient.downloadFile(pkg.url, pkg, this._logger, this._statusView, proxy, strictSSL).then(_ => {
|
||||
|
||||
this._logger.logDebug(`Downloaded to ${pkg.tmpFile.name}...`);
|
||||
this._logger.appendLine(' Done!');
|
||||
this.install(pkg).then(result => {
|
||||
resolve(true);
|
||||
}).catch(installError => {
|
||||
reject(installError);
|
||||
});
|
||||
}).catch(downloadError => {
|
||||
this._logger.appendLine(`[ERROR] ${downloadError}`);
|
||||
reject(downloadError);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createTempFile(pkg: IPackage): Promise<tmp.SynchronousResult> {
|
||||
return new Promise<tmp.SynchronousResult>((resolve, reject) => {
|
||||
tmp.file({ prefix: 'package-' }, (err, path, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
return reject(new PackageError('Error from tmp.file', pkg, err));
|
||||
}
|
||||
|
||||
resolve(<tmp.SynchronousResult>{ name: path, fd: fd, removeCallback: cleanupCallback });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private install(pkg: IPackage): Promise<void> {
|
||||
this._logger.appendLine('Installing ...');
|
||||
this._statusView.installingService();
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this._decompressProvider.decompress(pkg, this._logger).then(_ => {
|
||||
this._statusView.serviceInstalled();
|
||||
resolve();
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Runtime, PlatformInformation } from '../models/platform';
|
||||
import Config from '../configurations/config';
|
||||
import ServiceDownloadProvider from './serviceDownloadProvider';
|
||||
import DecompressProvider from './decompressProvider';
|
||||
import HttpClient from './httpClient';
|
||||
import ServerProvider from './server';
|
||||
import { IStatusView } from './interfaces';
|
||||
import { ILogger } from '../models/interfaces';
|
||||
import { IExtensionConstants } from '../models/contracts/contracts';
|
||||
|
||||
class StubStatusView implements IStatusView {
|
||||
installingService(): void {
|
||||
console.log('...');
|
||||
}
|
||||
serviceInstalled(): void {
|
||||
console.log('Service installed');
|
||||
}
|
||||
serviceInstallationFailed(): void {
|
||||
console.log('Service installation failed');
|
||||
}
|
||||
updateServiceDownloadingProgress(downloadPercentage: number): void {
|
||||
if (downloadPercentage === 100) {
|
||||
process.stdout.write('100%');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StubLogger implements ILogger {
|
||||
logDebug(message: string): void {
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
increaseIndent(): void {
|
||||
console.log('increaseIndent');
|
||||
}
|
||||
|
||||
decreaseIndent(): void {
|
||||
console.log('decreaseIndent');
|
||||
}
|
||||
|
||||
append(message?: string): void {
|
||||
process.stdout.write(message);
|
||||
}
|
||||
appendLine(message?: string): void {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
export class ServiceInstaller {
|
||||
private _config = undefined;
|
||||
private _logger = new StubLogger();
|
||||
private _statusView = new StubStatusView();
|
||||
private _httpClient = new HttpClient();
|
||||
private _decompressProvider = new DecompressProvider();
|
||||
private _downloadProvider = undefined;
|
||||
private _serverProvider = undefined;
|
||||
private _extensionConstants = undefined;
|
||||
|
||||
constructor(extensionConstants: IExtensionConstants, path?: string) {
|
||||
this._extensionConstants = extensionConstants;
|
||||
this._config = new Config(extensionConstants.extensionConfigSectionName, path, true);
|
||||
this._downloadProvider = new ServiceDownloadProvider(this._config, this._logger, this._statusView, this._httpClient, this._decompressProvider, extensionConstants, true);
|
||||
this._serverProvider = new ServerProvider(this._downloadProvider, this._config, this._statusView, extensionConstants.extensionConfigSectionName);
|
||||
}
|
||||
/*
|
||||
* Installs the service for the given platform if it's not already installed.
|
||||
*/
|
||||
public installService(): Promise<String> {
|
||||
return PlatformInformation.getCurrent(this._extensionConstants.getRuntimeId, this._extensionConstants.extensionName).then(platformInfo => {
|
||||
if (platformInfo.isValidRuntime()) {
|
||||
return this._serverProvider.getOrDownloadServer(platformInfo.runtimeId);
|
||||
} else {
|
||||
throw new Error('unsupported runtime');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the install folder path for given platform.
|
||||
*/
|
||||
public getServiceInstallDirectory(runtime: Runtime): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (runtime === undefined) {
|
||||
PlatformInformation.getCurrent(this._extensionConstants.getRuntimeId, this._extensionConstants.extensionName).then(platformInfo => {
|
||||
if (platformInfo.isValidRuntime()) {
|
||||
resolve(this._downloadProvider.getInstallDirectory(platformInfo.runtimeId));
|
||||
} else {
|
||||
reject('unsupported runtime');
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
resolve(this._downloadProvider.getInstallDirectory(runtime));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the path to the root folder of service install location.
|
||||
*/
|
||||
public getServiceInstallDirectoryRoot(runtime: Runtime): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (runtime === undefined) {
|
||||
PlatformInformation.getCurrent(this._extensionConstants.getRuntimeId, this._extensionConstants.extensionName).then(platformInfo => {
|
||||
if (platformInfo.isValidRuntime()) {
|
||||
let directoryPath: string = this._downloadProvider.getInstallDirectoryRoot(platformInfo, this._extensionConstants.extensionName);
|
||||
directoryPath = directoryPath.replace('\\{#version#}', '');
|
||||
directoryPath = directoryPath.replace('\\{#platform#}', '');
|
||||
directoryPath = directoryPath.replace('/{#platform#}', '');
|
||||
directoryPath = directoryPath.replace('/{#version#}', '');
|
||||
resolve(directoryPath);
|
||||
} else {
|
||||
reject('unsupported runtime');
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
resolve(this._downloadProvider.getInstallDirectory(runtime));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import vscode = require('vscode');
|
||||
|
||||
export default class ServiceStatus implements vscode.Disposable {
|
||||
|
||||
private _progressTimerId: NodeJS.Timer;
|
||||
|
||||
private _statusBarItem: vscode.StatusBarItem = undefined;
|
||||
|
||||
private durationStatusInMs: number = 1500;
|
||||
|
||||
// These need localization
|
||||
private _serviceStartingMessage: string = `Starting ${this._serviceName}`;
|
||||
private _serviceStartedMessage: string = `${this._serviceName} started`;
|
||||
|
||||
constructor(private _serviceName: string) {
|
||||
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
}
|
||||
|
||||
public showServiceLoading(): Promise<void> {
|
||||
return this === undefined ?
|
||||
Promise.resolve() :
|
||||
Promise.resolve(this.updateStatusView(this._serviceStartingMessage, true));
|
||||
}
|
||||
|
||||
public showServiceLoaded(): Promise<void> {
|
||||
return this === undefined ?
|
||||
Promise.resolve() :
|
||||
Promise.resolve(this.updateStatusView(this._serviceStartedMessage, false, this.durationStatusInMs));
|
||||
}
|
||||
|
||||
//TODO: This can be merged with the serverStatus code
|
||||
private showProgress(statusText: string): void {
|
||||
let index: number = 0;
|
||||
let progressTicks: string[] = ['.', '..', '...', '....'];
|
||||
|
||||
this._progressTimerId = setInterval(() => {
|
||||
index = (index + 1) % progressTicks.length;
|
||||
let progressTick = progressTicks[index];
|
||||
if (this._statusBarItem.text !== this._serviceStartedMessage) {
|
||||
this._statusBarItem.text = statusText + ' ' + progressTick;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
}, 400);
|
||||
}
|
||||
|
||||
private updateStatusView(message: string, showAsProgress: boolean = false, disposeAfter: number = -1): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (showAsProgress) {
|
||||
this.showProgress(message);
|
||||
}
|
||||
else {
|
||||
this._statusBarItem.text = message;
|
||||
this._statusBarItem.show();
|
||||
if (this._progressTimerId !== undefined) {
|
||||
clearInterval(this._progressTimerId);
|
||||
}
|
||||
}
|
||||
if (disposeAfter !== -1) {
|
||||
setInterval(() => {
|
||||
this._statusBarItem.hide();
|
||||
}, disposeAfter);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this._progressTimerId !== undefined) {
|
||||
clearInterval(this._progressTimerId);
|
||||
}
|
||||
this._statusBarItem.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export * from './controllers/vscodeWrapper';
|
||||
export * from './models/constants';
|
||||
export * from './models/utils';
|
||||
|
||||
export { SqlToolsServiceClient } from './languageservice/serviceClient';
|
||||
export { IExtensionConstants } from './models/contracts/contracts';
|
||||
export { ILanguageClientHelper } from './models/contracts/languageService';
|
||||
export { Runtime, PlatformInformation } from './models/platform';
|
||||
export { Telemetry } from './models/telemetry';
|
||||
export { LinuxDistribution } from './models/platform';
|
||||
export { ServiceInstaller } from './languageservice/serviceInstallerUtil';
|
||||
@@ -1,25 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export namespace Constants {
|
||||
//constants
|
||||
export const configLogDebugInfo: string = 'logDebugInfo';
|
||||
export const serviceNotCompatibleError: string = 'Client is not compatible with the service layer';
|
||||
export const serviceDownloading: string = 'Downloading';
|
||||
export const serviceInstalling: string = 'Installing';
|
||||
export const unsupportedPlatformErrorMessage: string = 'This platform is unsupported and application services may not function correctly';
|
||||
export const serviceConfigKey = 'service';
|
||||
export const executableFilesConfigKey = 'executableFiles';
|
||||
export const versionConfigKey = 'version';
|
||||
export const downloadUrlConfigKey = 'downloadUrl';
|
||||
export const installDirConfigKey = 'installDir';
|
||||
export const serviceCrashButton = 'View Known Issues';
|
||||
export const neverShowAgain = 'Do not show again';
|
||||
export const ignorePlatformWarning = 'ignorePlatformWarning';
|
||||
export const usingDefaultPlatformMessage = 'Unknown platform detected, defaulting to Linux_x64 platform';
|
||||
export const serverConnectionMetadata = 'serverConnectionMetadata';
|
||||
export const extensionDeactivated: string = 'de-activated.';
|
||||
export const extensionActivated: string = 'activated.';
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { RequestType } from 'vscode-languageclient';
|
||||
import { Runtime, LinuxDistribution } from '../platform';
|
||||
|
||||
// --------------------------------- < Version Request > -------------------------------------------------
|
||||
|
||||
// Version request message callback declaration
|
||||
export namespace VersionRequest {
|
||||
export const type = new RequestType<void, VersionResult, void, void>('version');
|
||||
}
|
||||
|
||||
// Version response format
|
||||
export type VersionResult = string;
|
||||
|
||||
// ------------------------------- </ Version Request > --------------------------------------------------
|
||||
|
||||
// Constants interface for each extension
|
||||
export interface IExtensionConstants {
|
||||
// TODO: Fill in interface
|
||||
|
||||
// Definitely dependent on the extension
|
||||
extensionName: string;
|
||||
invalidServiceFilePath: string;
|
||||
serviceName: string;
|
||||
extensionConfigSectionName: string;
|
||||
serviceCompatibleVersion: string;
|
||||
outputChannelName: string;
|
||||
languageId: string;
|
||||
serviceInstallingTo: string;
|
||||
serviceInitializing: string;
|
||||
serviceInstalled: string;
|
||||
serviceLoadingFailed: string;
|
||||
serviceInstallationFailed: string;
|
||||
serviceInitializingOutputChannelName: string;
|
||||
commandsNotAvailableWhileInstallingTheService: string;
|
||||
providerId: string;
|
||||
serviceCrashMessage: string;
|
||||
serviceCrashLink: string;
|
||||
installFolderName: string;
|
||||
telemetryExtensionName: string;
|
||||
|
||||
getRuntimeId(platform: string, architecture: string, distribution: LinuxDistribution): Runtime;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { NotificationType, ServerOptions, RequestType, RPCMessageType, ClientCapabilities, ServerCapabilities } from 'vscode-languageclient';
|
||||
import { ITelemetryEventProperties, ITelemetryEventMeasures } from '../telemetry';
|
||||
import { Runtime } from '../platform';
|
||||
import { SqlOpsFeature, SqlOpsDataClient } from 'dataprotocol-client';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import { Disposable } from 'vscode';
|
||||
|
||||
// ------------------------------- < Telemetry Sent Event > ------------------------------------
|
||||
|
||||
/**
|
||||
* Event sent when the language service send a telemetry event
|
||||
*/
|
||||
export namespace TelemetryNotification {
|
||||
export const type = new NotificationType<TelemetryParams, void>('telemetry/sqlevent');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update event parameters
|
||||
*/
|
||||
export class TelemetryParams {
|
||||
public params: {
|
||||
eventName: string;
|
||||
properties: ITelemetryEventProperties;
|
||||
measures: ITelemetryEventMeasures;
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------- </ Telemetry Sent Event > ----------------------------------
|
||||
|
||||
// ------------------------------- < Status Event > ------------------------------------
|
||||
|
||||
/**
|
||||
* Event sent when the language service send a status change event
|
||||
*/
|
||||
export namespace StatusChangedNotification {
|
||||
export const type = new NotificationType<StatusChangeParams, void>('textDocument/statusChanged');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update event parameters
|
||||
*/
|
||||
export class StatusChangeParams {
|
||||
/**
|
||||
* URI identifying the text document
|
||||
*/
|
||||
public ownerUri: string;
|
||||
|
||||
/**
|
||||
* The new status of the document
|
||||
*/
|
||||
public status: string;
|
||||
}
|
||||
|
||||
// ------------------------------- </ Status Sent Event > ----------------------------------
|
||||
|
||||
export interface ILanguageClientHelper {
|
||||
createServerOptions(servicePath: string, runtimeId?: Runtime): ServerOptions;
|
||||
}
|
||||
|
||||
// Job Management types
|
||||
export interface AgentJobsParams {
|
||||
ownerUri: string;
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
export interface AgentJobsResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
jobs: sqlops.AgentJobInfo[];
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryParams {
|
||||
ownerUri: string;
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
jobs: sqlops.AgentJobHistoryInfo[];
|
||||
}
|
||||
|
||||
export interface AgentJobActionParams {
|
||||
ownerUri: string;
|
||||
jobName: string;
|
||||
action: string;
|
||||
}
|
||||
|
||||
export interface AgentJobActionResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export namespace AgentJobsRequest {
|
||||
export const type = new RequestType<AgentJobsParams, AgentJobsResult, void, void>('agent/jobs');
|
||||
}
|
||||
|
||||
export namespace AgentJobHistoryRequest {
|
||||
export const type = new RequestType<AgentJobHistoryParams, AgentJobHistoryResult, void, void>('agent/jobhistory');
|
||||
}
|
||||
|
||||
|
||||
export namespace AgentJobActionRequest {
|
||||
export const type = new RequestType<AgentJobActionParams, AgentJobActionResult, void, void>('agent/jobaction');
|
||||
}
|
||||
|
||||
export class AgentServicesFeature extends SqlOpsFeature<undefined> {
|
||||
private static readonly messagesTypes: RPCMessageType[] = [
|
||||
AgentJobsRequest.type,
|
||||
AgentJobHistoryRequest.type,
|
||||
AgentJobActionRequest.type
|
||||
];
|
||||
|
||||
constructor(client: SqlOpsDataClient) {
|
||||
super(client, AgentServicesFeature.messagesTypes);
|
||||
}
|
||||
|
||||
public fillClientCapabilities(capabilities: ClientCapabilities): void {
|
||||
// this isn't explicitly necessary
|
||||
// ensure(ensure(capabilities, 'connection')!, 'agentServices')!.dynamicRegistration = true;
|
||||
}
|
||||
|
||||
public initialize(capabilities: ServerCapabilities): void {
|
||||
this.register(this.messages, {
|
||||
id: UUID.generateUuid(),
|
||||
registerOptions: undefined
|
||||
});
|
||||
}
|
||||
|
||||
protected registerProvider(options: undefined): Disposable {
|
||||
const client = this._client;
|
||||
|
||||
let getJobs = (ownerUri: string): Thenable<sqlops.AgentJobsResult> => {
|
||||
let params: AgentJobsParams = { ownerUri: ownerUri, jobId: null };
|
||||
return client.sendRequest(AgentJobsRequest.type, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(AgentJobsRequest.type, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let getJobHistory = (connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> => {
|
||||
let params: AgentJobHistoryParams = { ownerUri: connectionUri, jobId: jobID };
|
||||
|
||||
return client.sendRequest(AgentJobHistoryRequest.type, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(AgentJobHistoryRequest.type, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let jobAction = (connectionUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> => {
|
||||
let params: AgentJobActionParams = { ownerUri: connectionUri, jobName: jobName, action: action };
|
||||
return client.sendRequest(AgentJobActionRequest.type, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(AgentJobActionRequest.type, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return sqlops.dataprotocol.registerAgentServicesProvider({
|
||||
providerId: client.providerId,
|
||||
getJobs,
|
||||
getJobHistory,
|
||||
jobAction
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ILogger } from './interfaces';
|
||||
import { Utils } from './utils';
|
||||
import { IExtensionConstants } from './contracts/contracts';
|
||||
|
||||
/*
|
||||
* Logger class handles logging messages using the Util functions.
|
||||
*/
|
||||
export class Logger implements ILogger {
|
||||
private _writer: (message: string) => void;
|
||||
private _prefix: string;
|
||||
private _extensionConstants: IExtensionConstants;
|
||||
|
||||
private _indentLevel: number = 0;
|
||||
private _indentSize: number = 4;
|
||||
private _atLineStart: boolean = false;
|
||||
|
||||
constructor(writer: (message: string) => void, extensionConstants: IExtensionConstants, prefix?: string) {
|
||||
this._writer = writer;
|
||||
this._prefix = prefix;
|
||||
this._extensionConstants = extensionConstants;
|
||||
}
|
||||
|
||||
public logDebug(message: string): void {
|
||||
Utils.logDebug(message, this._extensionConstants.extensionConfigSectionName);
|
||||
}
|
||||
|
||||
private _appendCore(message: string): void {
|
||||
if (this._atLineStart) {
|
||||
if (this._indentLevel > 0) {
|
||||
const indent = ' '.repeat(this._indentLevel * this._indentSize);
|
||||
this._writer(indent);
|
||||
}
|
||||
|
||||
if (this._prefix) {
|
||||
this._writer(`[${this._prefix}] `);
|
||||
}
|
||||
|
||||
this._atLineStart = false;
|
||||
}
|
||||
|
||||
this._writer(message);
|
||||
}
|
||||
|
||||
public increaseIndent(): void {
|
||||
this._indentLevel += 1;
|
||||
}
|
||||
|
||||
public decreaseIndent(): void {
|
||||
if (this._indentLevel > 0) {
|
||||
this._indentLevel -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public append(message?: string): void {
|
||||
message = message || '';
|
||||
this._appendCore(message);
|
||||
}
|
||||
|
||||
public appendLine(message?: string): void {
|
||||
message = message || '';
|
||||
this._appendCore(message + os.EOL);
|
||||
this._atLineStart = true;
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as child_process from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
|
||||
const unknown = 'unknown';
|
||||
|
||||
export enum Runtime {
|
||||
UnknownRuntime = <any>'Unknown',
|
||||
UnknownVersion = <any>'Unknown',
|
||||
Windows_86 = <any>'Windows_86',
|
||||
Windows_64 = <any>'Windows_64',
|
||||
OSX = <any>'OSX',
|
||||
CentOS_7 = <any>'CentOS_7',
|
||||
Debian_8 = <any>'Debian_8',
|
||||
Fedora_23 = <any>'Fedora_23',
|
||||
OpenSUSE_13_2 = <any>'OpenSUSE_13_2',
|
||||
SLES_12_2 = <any>'SLES_12_2',
|
||||
RHEL_7 = <any>'RHEL_7',
|
||||
Ubuntu_14 = <any>'Ubuntu_14',
|
||||
Ubuntu_16 = <any>'Ubuntu_16',
|
||||
Linux_64 = <any>'Linux_64',
|
||||
Linux_86 = <any>'Linux-86'
|
||||
}
|
||||
|
||||
export function getRuntimeDisplayName(runtime: Runtime): string {
|
||||
switch (runtime) {
|
||||
case Runtime.Windows_64:
|
||||
return 'Windows';
|
||||
case Runtime.Windows_86:
|
||||
return 'Windows';
|
||||
case Runtime.OSX:
|
||||
return 'OSX';
|
||||
case Runtime.CentOS_7:
|
||||
return 'Linux';
|
||||
case Runtime.Debian_8:
|
||||
return 'Linux';
|
||||
case Runtime.Fedora_23:
|
||||
return 'Linux';
|
||||
case Runtime.OpenSUSE_13_2:
|
||||
return 'Linux';
|
||||
case Runtime.SLES_12_2:
|
||||
return 'Linux';
|
||||
case Runtime.RHEL_7:
|
||||
return 'Linux';
|
||||
case Runtime.Ubuntu_14:
|
||||
return 'Linux';
|
||||
case Runtime.Ubuntu_16:
|
||||
return 'Linux';
|
||||
case Runtime.Linux_64:
|
||||
return 'Linux';
|
||||
case Runtime.Linux_86:
|
||||
return 'Linux';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
export class PlatformInformation {
|
||||
public runtimeId: Runtime;
|
||||
|
||||
public constructor(
|
||||
public platform: string,
|
||||
public architecture: string,
|
||||
public distribution: LinuxDistribution = undefined,
|
||||
public getRuntimeId: (platform: string, architecture: string, distribution: LinuxDistribution) => Runtime) {
|
||||
try {
|
||||
this.runtimeId = this.getRuntimeId(platform, architecture, distribution);
|
||||
} catch (err) {
|
||||
this.runtimeId = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public isWindows(): boolean {
|
||||
return this.platform === 'win32';
|
||||
}
|
||||
|
||||
public isMacOS(): boolean {
|
||||
return this.platform === 'darwin';
|
||||
}
|
||||
|
||||
public isLinux(): boolean {
|
||||
return this.platform === 'linux';
|
||||
}
|
||||
|
||||
public isValidRuntime(): boolean {
|
||||
return this.runtimeId !== undefined && this.runtimeId !== Runtime.UnknownRuntime && this.runtimeId !== Runtime.UnknownVersion;
|
||||
}
|
||||
|
||||
public getRuntimeDisplayName(): string {
|
||||
return getRuntimeDisplayName(this.runtimeId);
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
let result = this.platform;
|
||||
|
||||
if (this.architecture) {
|
||||
if (result) {
|
||||
result += ', ';
|
||||
}
|
||||
|
||||
result += this.architecture;
|
||||
}
|
||||
|
||||
if (this.distribution) {
|
||||
if (result) {
|
||||
result += ', ';
|
||||
}
|
||||
|
||||
result += this.distribution.toString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static getCurrent(getRuntimeId: (platform: string, architecture: string, distribution: LinuxDistribution) => Runtime,
|
||||
extensionName: string): Promise<any> {
|
||||
let platform = os.platform();
|
||||
let architecturePromise: Promise<string>;
|
||||
let distributionPromise: Promise<LinuxDistribution>;
|
||||
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
architecturePromise = PlatformInformation.getWindowsArchitecture();
|
||||
distributionPromise = Promise.resolve(undefined);
|
||||
break;
|
||||
|
||||
case 'darwin':
|
||||
let osVersion = os.release();
|
||||
if (parseFloat(osVersion) < 16.0 && extensionName === 'mssql') {
|
||||
return Promise.reject('The current version of macOS is not supported. Only macOS Sierra and above (>= 10.12) are supported.');
|
||||
}
|
||||
architecturePromise = PlatformInformation.getUnixArchitecture();
|
||||
distributionPromise = Promise.resolve(undefined);
|
||||
break;
|
||||
|
||||
case 'linux':
|
||||
architecturePromise = PlatformInformation.getUnixArchitecture();
|
||||
distributionPromise = LinuxDistribution.getCurrent();
|
||||
break;
|
||||
|
||||
default:
|
||||
return Promise.reject(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
|
||||
return architecturePromise.then(arch => {
|
||||
return distributionPromise.then(distro => {
|
||||
return new PlatformInformation(platform, arch, distro, getRuntimeId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static getWindowsArchitecture(): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
// try to get the architecture from WMIC
|
||||
PlatformInformation.getWindowsArchitectureWmic().then(architecture => {
|
||||
if (architecture && architecture !== unknown) {
|
||||
resolve(architecture);
|
||||
} else {
|
||||
// sometimes WMIC isn't available on the path so then try to parse the envvar
|
||||
PlatformInformation.getWindowsArchitectureEnv().then(architecture => {
|
||||
resolve(architecture);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static getWindowsArchitectureWmic(): Promise<string> {
|
||||
return this.execChildProcess('wmic os get osarchitecture')
|
||||
.then(architecture => {
|
||||
if (architecture) {
|
||||
let archArray: string[] = architecture.split(os.EOL);
|
||||
if (archArray.length >= 2) {
|
||||
let arch = archArray[1].trim();
|
||||
|
||||
// Note: This string can be localized. So, we'll just check to see if it contains 32 or 64.
|
||||
if (arch.indexOf('64') >= 0) {
|
||||
return 'x86_64';
|
||||
} else if (arch.indexOf('32') >= 0) {
|
||||
return 'x86';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unknown;
|
||||
}).catch((error) => {
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
private static getWindowsArchitectureEnv(): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (process.env.PROCESSOR_ARCHITECTURE === 'x86' && process.env.PROCESSOR_ARCHITEW6432 === undefined) {
|
||||
resolve('x86');
|
||||
}
|
||||
else {
|
||||
resolve('x86_64');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static getUnixArchitecture(): Promise<string> {
|
||||
return this.execChildProcess('uname -m')
|
||||
.then(architecture => {
|
||||
if (architecture) {
|
||||
return architecture.trim();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
private static execChildProcess(process: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
child_process.exec(process, { maxBuffer: 500 * 1024 }, (error: Error, stdout: string, stderr: string) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stderr && stderr.length > 0) {
|
||||
reject(new Error(stderr));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(stdout);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no standard way on Linux to find the distribution name and version.
|
||||
* Recently, systemd has pushed to standardize the os-release file. This has
|
||||
* seen adoption in "recent" versions of all major distributions.
|
||||
* https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||
*/
|
||||
export class LinuxDistribution {
|
||||
public constructor(
|
||||
public name: string,
|
||||
public version: string,
|
||||
public idLike?: string[]) { }
|
||||
|
||||
public static getCurrent(): Promise<LinuxDistribution> {
|
||||
// Try /etc/os-release and fallback to /usr/lib/os-release per the synopsis
|
||||
// at https://www.freedesktop.org/software/systemd/man/os-release.html.
|
||||
return LinuxDistribution.fromFilePath('/etc/os-release')
|
||||
.catch(() => LinuxDistribution.fromFilePath('/usr/lib/os-release'))
|
||||
.catch(() => Promise.resolve(new LinuxDistribution(unknown, unknown)));
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return `name=${this.name}, version=${this.version}`;
|
||||
}
|
||||
|
||||
private static fromFilePath(filePath: string): Promise<LinuxDistribution> {
|
||||
return new Promise<LinuxDistribution>((resolve, reject) => {
|
||||
fs.readFile(filePath, 'utf8', (error, data) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(LinuxDistribution.fromReleaseInfo(data));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static fromReleaseInfo(releaseInfo: string, eol: string = os.EOL): LinuxDistribution {
|
||||
let name = unknown;
|
||||
let version = unknown;
|
||||
let idLike: string[] = undefined;
|
||||
|
||||
const lines = releaseInfo.split(eol);
|
||||
for (let line of lines) {
|
||||
line = line.trim();
|
||||
|
||||
let equalsIndex = line.indexOf('=');
|
||||
if (equalsIndex >= 0) {
|
||||
let key = line.substring(0, equalsIndex);
|
||||
let value = line.substring(equalsIndex + 1);
|
||||
|
||||
// Strip quotes if necessary
|
||||
if (value.length > 1 && value.startsWith('"') && value.endsWith('"')) {
|
||||
value = value.substring(1, value.length - 1);
|
||||
} else if (value.length > 1 && value.startsWith('\'') && value.endsWith('\'')) {
|
||||
value = value.substring(1, value.length - 1);
|
||||
}
|
||||
|
||||
if (key === 'ID') {
|
||||
name = value;
|
||||
} else if (key === 'VERSION_ID') {
|
||||
version = value;
|
||||
} else if (key === 'ID_LIKE') {
|
||||
idLike = value.split(' ');
|
||||
}
|
||||
|
||||
if (name !== unknown && version !== unknown && idLike !== undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new LinuxDistribution(name, version, idLike);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import * as crypto from 'crypto';
|
||||
import * as os from 'os';
|
||||
import vscode = require('vscode');
|
||||
import { Constants } from './constants';
|
||||
import { ExtensionContext } from 'vscode';
|
||||
var path = require('path');
|
||||
|
||||
export namespace Utils {
|
||||
// INTERFACES /////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Interface for package.json information
|
||||
export interface IPackageInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
aiKey: string;
|
||||
}
|
||||
|
||||
// FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Get information from the extension's package.json file
|
||||
export function getPackageInfo(context: ExtensionContext): IPackageInfo {
|
||||
let extensionPackage = require(context.asAbsolutePath('./package.json'));
|
||||
if (extensionPackage) {
|
||||
return {
|
||||
name: extensionPackage.name,
|
||||
version: extensionPackage.version,
|
||||
aiKey: extensionPackage.aiKey
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a new GUID
|
||||
export function generateGuid(): string {
|
||||
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
|
||||
// c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
|
||||
let oct: string = '';
|
||||
let tmp: number;
|
||||
/* tslint:disable:no-bitwise */
|
||||
for (let a: number = 0; a < 4; a++) {
|
||||
tmp = (4294967296 * Math.random()) | 0;
|
||||
oct += hexValues[tmp & 0xF] +
|
||||
hexValues[tmp >> 4 & 0xF] +
|
||||
hexValues[tmp >> 8 & 0xF] +
|
||||
hexValues[tmp >> 12 & 0xF] +
|
||||
hexValues[tmp >> 16 & 0xF] +
|
||||
hexValues[tmp >> 20 & 0xF] +
|
||||
hexValues[tmp >> 24 & 0xF] +
|
||||
hexValues[tmp >> 28 & 0xF];
|
||||
}
|
||||
|
||||
// 'Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively'
|
||||
let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0];
|
||||
return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12);
|
||||
/* tslint:enable:no-bitwise */
|
||||
}
|
||||
|
||||
// Generate a unique, deterministic ID for the current user of the extension
|
||||
export function generateUserId(): Promise<string> {
|
||||
return new Promise<string>(resolve => {
|
||||
try {
|
||||
let interfaces = os.networkInterfaces();
|
||||
let mac;
|
||||
for (let key of Object.keys(interfaces)) {
|
||||
let item = interfaces[key][0];
|
||||
if (!item.internal) {
|
||||
mac = item.mac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mac) {
|
||||
resolve(crypto.createHash('sha256').update(mac + os.homedir(), 'utf8').digest('hex'));
|
||||
} else {
|
||||
resolve(generateGuid());
|
||||
}
|
||||
} catch (err) {
|
||||
resolve(generateGuid()); // fallback
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Retrieve the URI for the currently open file if there is one; otherwise return the empty string
|
||||
export function getActiveTextEditorUri(): string {
|
||||
if (typeof vscode.window.activeTextEditor !== 'undefined' &&
|
||||
typeof vscode.window.activeTextEditor.document !== 'undefined') {
|
||||
return vscode.window.activeTextEditor.document.uri.toString();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Helper to log debug messages
|
||||
export function logDebug(msg: any, extensionConfigSectionName: string): void {
|
||||
let config = vscode.workspace.getConfiguration(extensionConfigSectionName);
|
||||
let logDebugInfo = config[Constants.configLogDebugInfo];
|
||||
if (logDebugInfo === true) {
|
||||
let currentTime = new Date().toLocaleTimeString();
|
||||
let outputMsg = '[' + currentTime + ']: ' + msg ? msg.toString() : '';
|
||||
console.log(outputMsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to show an error message
|
||||
export function showErrorMsg(msg: string, extensionName: string): void {
|
||||
vscode.window.showErrorMessage(extensionName + ': ' + msg);
|
||||
}
|
||||
|
||||
export function isEmpty(str: any): boolean {
|
||||
return (!str || '' === str);
|
||||
}
|
||||
|
||||
// The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't
|
||||
// work for now because the extension is running in different process.
|
||||
export function getAppDataPath() {
|
||||
var platform = process.platform;
|
||||
switch (platform) {
|
||||
case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE'], 'AppData', 'Roaming');
|
||||
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support');
|
||||
case 'linux': return process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config');
|
||||
default: throw new Error('Platform not supported');
|
||||
}
|
||||
}
|
||||
|
||||
export function getDefaultLogLocation() {
|
||||
return path.join(getAppDataPath(), 'sqlops');
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "../lib",
|
||||
"lib": [
|
||||
"es6", "es2015.promise"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import vscode = require('vscode');
|
||||
import { Utils } from '../models/utils';
|
||||
|
||||
// Status bar element for each file in the editor
|
||||
class FileStatusBar {
|
||||
// Item for the connection status
|
||||
public statusConnection: vscode.StatusBarItem;
|
||||
|
||||
// Item for the query status
|
||||
public statusQuery: vscode.StatusBarItem;
|
||||
|
||||
// Item for language service status
|
||||
public statusLanguageService: vscode.StatusBarItem;
|
||||
|
||||
// Timer used for displaying a progress indicator on queries
|
||||
public progressTimerId: NodeJS.Timer;
|
||||
|
||||
public currentLanguageServiceStatus: string;
|
||||
}
|
||||
|
||||
export default class StatusView implements vscode.Disposable {
|
||||
private _statusBars: { [fileUri: string]: FileStatusBar };
|
||||
private _lastShownStatusBar: FileStatusBar;
|
||||
|
||||
constructor() {
|
||||
this._statusBars = {};
|
||||
vscode.window.onDidChangeActiveTextEditor((params) => this.onDidChangeActiveTextEditor(params));
|
||||
vscode.workspace.onDidCloseTextDocument((params) => this.onDidCloseTextDocument(params));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (let bar in this._statusBars) {
|
||||
if (this._statusBars.hasOwnProperty(bar)) {
|
||||
this._statusBars[bar].statusConnection.dispose();
|
||||
this._statusBars[bar].statusQuery.dispose();
|
||||
this._statusBars[bar].statusLanguageService.dispose();
|
||||
clearInterval(this._statusBars[bar].progressTimerId);
|
||||
delete this._statusBars[bar];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create status bar item if needed
|
||||
private createStatusBar(fileUri: string): void {
|
||||
let bar = new FileStatusBar();
|
||||
bar.statusConnection = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
bar.statusQuery = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
bar.statusLanguageService = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
this._statusBars[fileUri] = bar;
|
||||
}
|
||||
|
||||
private destroyStatusBar(fileUri: string): void {
|
||||
let bar = this._statusBars[fileUri];
|
||||
if (bar) {
|
||||
if (bar.statusConnection) {
|
||||
bar.statusConnection.dispose();
|
||||
}
|
||||
if (bar.statusQuery) {
|
||||
bar.statusQuery.dispose();
|
||||
}
|
||||
if (bar.statusLanguageService) {
|
||||
bar.statusLanguageService.dispose();
|
||||
}
|
||||
if (bar.progressTimerId) {
|
||||
clearInterval(bar.progressTimerId);
|
||||
}
|
||||
|
||||
delete this._statusBars[fileUri];
|
||||
}
|
||||
}
|
||||
|
||||
private getStatusBar(fileUri: string): FileStatusBar {
|
||||
if (!(fileUri in this._statusBars)) {
|
||||
// Create it if it does not exist
|
||||
this.createStatusBar(fileUri);
|
||||
}
|
||||
|
||||
let bar = this._statusBars[fileUri];
|
||||
if (bar.progressTimerId) {
|
||||
clearInterval(bar.progressTimerId);
|
||||
}
|
||||
return bar;
|
||||
}
|
||||
|
||||
public languageServiceStatusChanged(fileUri: string, status: string): void {
|
||||
let bar = this.getStatusBar(fileUri);
|
||||
bar.currentLanguageServiceStatus = status;
|
||||
this.updateStatusMessage(status,
|
||||
() => { return bar.currentLanguageServiceStatus; }, (message) => {
|
||||
bar.statusLanguageService.text = message;
|
||||
this.showStatusBarItem(fileUri, bar.statusLanguageService);
|
||||
});
|
||||
}
|
||||
|
||||
public updateStatusMessage(
|
||||
newStatus: string,
|
||||
getCurrentStatus: () => string,
|
||||
updateMessage: (message: string) => void): void {
|
||||
}
|
||||
|
||||
private hideLastShownStatusBar(): void {
|
||||
if (typeof this._lastShownStatusBar !== 'undefined') {
|
||||
this._lastShownStatusBar.statusConnection.hide();
|
||||
this._lastShownStatusBar.statusQuery.hide();
|
||||
this._lastShownStatusBar.statusLanguageService.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
|
||||
// Hide the most recently shown status bar
|
||||
this.hideLastShownStatusBar();
|
||||
|
||||
// Change the status bar to match the open file
|
||||
if (typeof editor !== 'undefined') {
|
||||
const fileUri = editor.document.uri.toString();
|
||||
const bar = this._statusBars[fileUri];
|
||||
if (bar) {
|
||||
this.showStatusBarItem(fileUri, bar.statusConnection);
|
||||
this.showStatusBarItem(fileUri, bar.statusLanguageService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onDidCloseTextDocument(doc: vscode.TextDocument): void {
|
||||
// Remove the status bar associated with the document
|
||||
this.destroyStatusBar(doc.uri.toString());
|
||||
}
|
||||
|
||||
private showStatusBarItem(fileUri: string, statusBarItem: vscode.StatusBarItem): void {
|
||||
let currentOpenFile = Utils.getActiveTextEditorUri();
|
||||
|
||||
// Only show the status bar if it matches the currently open file and is not empty
|
||||
if (fileUri === currentOpenFile && !Utils.isEmpty(statusBarItem.text)) {
|
||||
statusBarItem.show();
|
||||
if (fileUri in this._statusBars) {
|
||||
this._lastShownStatusBar = this._statusBars[fileUri];
|
||||
}
|
||||
} else {
|
||||
statusBarItem.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"adal-node": "0.1.25",
|
||||
"request": "2.63.0",
|
||||
"vscode-nls": "2.0.2"
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^8.0.24"
|
||||
@@ -19,8 +19,8 @@
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "extension.clearTokenCache",
|
||||
"title": "%extension.clearTokenCache%",
|
||||
"command": "accounts.clearTokenCache",
|
||||
"title": "%accounts.clearTokenCache%",
|
||||
"category": "Azure Accounts"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extension.clearTokenCache": "Clear Azure Account Token Cache",
|
||||
"accounts.clearTokenCache": "Clear Azure Account Token Cache",
|
||||
"config.enablePublicCloudDescription": "Should Azure public cloud integration be enabled",
|
||||
"config.enableUsGovCloudDescription": "Should US Government Azure cloud (Fairfax) integration be enabled",
|
||||
"config.enableChinaCloudDescription": "Should Azure China integration be enabled",
|
||||
|
||||
@@ -20,7 +20,7 @@ let localize = nls.loadMessageBundle();
|
||||
|
||||
export class AzureAccountProviderService implements vscode.Disposable {
|
||||
// CONSTANTS ///////////////////////////////////////////////////////////////
|
||||
private static CommandClearTokenCache = 'extension.clearTokenCache';
|
||||
private static CommandClearTokenCache = 'accounts.azure.clearTokenCache';
|
||||
private static ConfigurationSection = 'accounts.azure';
|
||||
private static CredentialNamespace = 'azureAccountProviderCredentials';
|
||||
|
||||
|
||||
@@ -591,9 +591,9 @@ verror@1.10.0:
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
vscode-nls@2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
|
||||
"xmldom@>= 0.1.x":
|
||||
version "0.1.27"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs (early preview)",
|
||||
"version": "0.27.1",
|
||||
"version": "0.28.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/LICENSE.txt",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"name": "bat",
|
||||
"version": "0.1.0",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"version": "1.0.0",
|
||||
"publisher": "vscode",
|
||||
"engines": { "vscode": "*" },
|
||||
"scripts": {
|
||||
|
||||
4
extensions/bat/package.nls.json
Normal file
4
extensions/bat/package.nls.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Windows Bat Language Basics",
|
||||
"description": "Provides snippets, syntax highlighting, bracket matching and folding in Windows batch files."
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>uuid</key>
|
||||
<string>E07EC438-7B75-4437-8AA1-DA94C1E6EACC</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.command.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?i)(?:append|assoc|at|attrib|break|cacls|cd|chcp|chdir|chkdsk|chkntfs|cls|cmd|color|comp|compact|convert|copy|date|del|dir|diskcomp|diskcopy|doskey|echo|endlocal|erase|fc|find|findstr|format|ftype|graftabl|help|keyb|label|md|mkdir|mode|more|move|path|pause|popd|print|prompt|pushd|rd|recover|ren|rename|replace|restore|rmdir|set|setlocal|shift|sort|start|subst|time|title|tree|type|ver|verify|vol|xcopy)\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.control.statement.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?i)(?:goto|call|exit)\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.control.conditional.if.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?i)if\s+((not)\s+)(exist|defined|errorlevel|cmdextversion)\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.control.conditional.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?i)(?:if|else)\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.control.repeat.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?i)for\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.operator.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?:EQU|NEQ|LSS|LEQ|GTR|GEQ)\b</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>comment.line.rem.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\b(?i)rem(?:$|\s.*$)</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>comment.line.colons.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>\s*:\s*:.*$</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>variable.parameter.function.begin.shell</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>variable.parameter.function.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>(?i)(%)(~(?:f|d|p|n|x|s|a|t|z|\$[^:]*:)*)?\d</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>variable.other.parsetime.begin.shell</string>
|
||||
</dict>
|
||||
<key>2</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>variable.other.parsetime.end.shell</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>variable.other.parsetime.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>(%)[^%]+(%)|(%%)[^%]+(%%)</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>variable.parameter.loop.begin.shell</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>variable.parameter.loop.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>(?i)(%%)(~(?:f|d|p|n|x|s|a|t|z|\$[^:]*:)*)?[a-z]</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>variable.other.delayed.begin.shell</string>
|
||||
</dict>
|
||||
<key>2</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>variable.other.delayed.end.shell</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>variable.other.delayed.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>(!)[^!]+(!)</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>"</string>
|
||||
<key>endCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.string.end.shell</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>beginCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.string.begin.shell</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>string.quoted.double.dosbatch</string>
|
||||
<key>end</key>
|
||||
<string>"|$</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.operator.pipe.dosbatch</string>
|
||||
<key>match</key>
|
||||
<string>[|]</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>keyword.operator.redirect.shell</string>
|
||||
<key>match</key>
|
||||
<string>&>|\d*>&\d*|\d*(>>|>|<)|\d*<&|\d*<></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>name</key>
|
||||
<string>Batch File</string>
|
||||
<key>scopeName</key>
|
||||
<string>source.dosbatch</string>
|
||||
<key>fileTypes</key>
|
||||
<array>
|
||||
<string>bat</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -4,13 +4,9 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/mmims/language-batchfile/commit/40b605c75db3967a24b7015f6d3a885360b84e28",
|
||||
"scopeName": "source.batchfile",
|
||||
"version": "https://github.com/mmims/language-batchfile/commit/3dd105c31484e5975144478dac1aa91d8f51e528",
|
||||
"name": "Batch File",
|
||||
"fileTypes": [
|
||||
"bat",
|
||||
"cmd"
|
||||
],
|
||||
"scopeName": "source.batchfile",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#commands"
|
||||
@@ -454,11 +450,15 @@
|
||||
{
|
||||
"begin": "\\(",
|
||||
"beginCaptures": {
|
||||
"0": "punctuation.section.group.begin.batchfile"
|
||||
"0": {
|
||||
"name": "punctuation.section.group.begin.batchfile"
|
||||
}
|
||||
},
|
||||
"end": "\\)",
|
||||
"endCaptures": {
|
||||
"0": "punctuation.section.group.end.batchfile"
|
||||
"0": {
|
||||
"name": "punctuation.section.group.end.batchfile"
|
||||
}
|
||||
},
|
||||
"name": "meta.group.batchfile",
|
||||
"patterns": [
|
||||
|
||||
15
extensions/configuration-editing/npm-shrinkwrap.json
generated
15
extensions/configuration-editing/npm-shrinkwrap.json
generated
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "configuration-editing",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"jsonc-parser": {
|
||||
"version": "0.3.1",
|
||||
"from": "jsonc-parser@0.3.1"
|
||||
},
|
||||
"vscode-nls": {
|
||||
"version": "2.0.2",
|
||||
"from": "vscode-nls@>=2.0.2 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"name": "configuration-editing",
|
||||
"version": "0.0.1",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"version": "1.0.0",
|
||||
"publisher": "vscode",
|
||||
"engines": {
|
||||
"vscode": "^1.0.0"
|
||||
@@ -10,7 +12,8 @@
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:json", "onLanguage:jsonc"
|
||||
"onLanguage:json",
|
||||
"onLanguage:jsonc"
|
||||
],
|
||||
"main": "./out/extension",
|
||||
"scripts": {
|
||||
@@ -18,8 +21,8 @@
|
||||
"watch": "gulp watch-extension:configuration-editing"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^0.3.1",
|
||||
"vscode-nls": "^2.0.1"
|
||||
"jsonc-parser": "^1.0.0",
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"contributes": {
|
||||
"jsonValidation": [
|
||||
@@ -67,6 +70,10 @@
|
||||
"fileMatch": "%APP_SETTINGS_HOME%/snippets/*.json",
|
||||
"url": "vscode://schemas/snippets"
|
||||
},
|
||||
{
|
||||
"fileMatch": "**/*.code-snippets",
|
||||
"url": "vscode://schemas/global-snippets"
|
||||
},
|
||||
{
|
||||
"fileMatch": "/.vscode/extensions.json",
|
||||
"url": "vscode://schemas/extensions"
|
||||
@@ -76,4 +83,4 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
4
extensions/configuration-editing/package.nls.json
Normal file
4
extensions/configuration-editing/package.nls.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Configuration Editing",
|
||||
"description": "Provides capabilities (advanced IntelliSense, auto-fixing) in configuration files like settings, launch and extension recommendation files."
|
||||
}
|
||||
@@ -2,16 +2,14 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
import * as vscode from 'vscode';
|
||||
import { getLocation, visit, parse } from 'jsonc-parser';
|
||||
import { getLocation, visit, parse, ParseErrorCode } from 'jsonc-parser';
|
||||
import * as path from 'path';
|
||||
import { SettingsDocument } from './settingsDocumentHelper';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
const decoration = vscode.window.createTextEditorDecorationType({
|
||||
color: '#9e9e9e'
|
||||
@@ -20,7 +18,6 @@ const decoration = vscode.window.createTextEditorDecorationType({
|
||||
let pendingLaunchJsonDecoration: NodeJS.Timer;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
|
||||
//keybindings.json command-suggestions
|
||||
context.subscriptions.push(registerKeybindingsCompletions());
|
||||
|
||||
@@ -41,6 +38,45 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
}
|
||||
}, null, context.subscriptions));
|
||||
updateLaunchJsonDecorations(vscode.window.activeTextEditor);
|
||||
|
||||
context.subscriptions.push(vscode.workspace.onWillSaveTextDocument(e => {
|
||||
if (!e.document.fileName.endsWith('/settings.json')) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoFixSettingsJSON(e);
|
||||
}));
|
||||
}
|
||||
|
||||
function autoFixSettingsJSON(willSaveEvent: vscode.TextDocumentWillSaveEvent): void {
|
||||
const document = willSaveEvent.document;
|
||||
const text = document.getText();
|
||||
const edit = new vscode.WorkspaceEdit();
|
||||
|
||||
let lastEndOfSomething = -1;
|
||||
visit(text, {
|
||||
onArrayEnd(offset: number, length: number): void {
|
||||
lastEndOfSomething = offset + length;
|
||||
},
|
||||
|
||||
onLiteralValue(value: any, offset: number, length: number): void {
|
||||
lastEndOfSomething = offset + length;
|
||||
},
|
||||
|
||||
onObjectEnd(offset: number, length: number): void {
|
||||
lastEndOfSomething = offset + length;
|
||||
},
|
||||
|
||||
onError(error: ParseErrorCode, offset: number, length: number): void {
|
||||
if (error === ParseErrorCode.CommaExpected && lastEndOfSomething > -1) {
|
||||
const fixPosition = document.positionAt(lastEndOfSomething);
|
||||
edit.insert(document.uri, fixPosition, ',');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
willSaveEvent.waitUntil(
|
||||
vscode.workspace.applyEdit(edit));
|
||||
}
|
||||
|
||||
function registerKeybindingsCompletions(): vscode.Disposable {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user