inserted async-io
This commit is contained in:
Родитель
3e62a675df
Коммит
f2dd7560d6
|
@ -1,11 +1,19 @@
|
|||
dependencies:
|
||||
'@rush-temp/async-io': 'file:projects/async-io.tgz'
|
||||
'@rush-temp/tasks': 'file:projects/tasks.tgz'
|
||||
'@types/mocha': 5.2.5
|
||||
'@types/node': 10.11.3
|
||||
'@types/pify': 0.0.28
|
||||
file-url: 2.0.2
|
||||
get-uri: 2.0.2
|
||||
mocha: 5.2.0
|
||||
mocha-typescript: 1.1.17
|
||||
pify: 2.3.0
|
||||
proper-lockfile: 2.0.1
|
||||
source-map-support: 0.5.9
|
||||
strip-bom: 3.0.0
|
||||
typescript: 3.1.1
|
||||
urijs: 1.18.12
|
||||
packages:
|
||||
/@types/mocha/5.2.5:
|
||||
dev: false
|
||||
|
@ -15,6 +23,10 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-3AvcEJAh9EMatxs+OxAlvAEs7OTy6AG94mcH1iqyVDwVVndekLxzwkWQ/Z4SDbY6GO2oyUXyWW8tQ4rENSSQVQ==
|
||||
/@types/pify/0.0.28:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-aCtsM6HQV0i4bwKb2rb2Kqc/9QY=
|
||||
/ansi-regex/2.1.1:
|
||||
dev: false
|
||||
engines:
|
||||
|
@ -103,6 +115,10 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
/core-util-is/1.0.2:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
/cross-spawn/5.1.0:
|
||||
dependencies:
|
||||
lru-cache: 4.1.3
|
||||
|
@ -123,6 +139,16 @@ packages:
|
|||
node: '>=4.8'
|
||||
resolution:
|
||||
integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
|
||||
/data-uri-to-buffer/1.2.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==
|
||||
/debug/2.6.9:
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
/debug/3.1.0:
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
|
@ -141,10 +167,6 @@ packages:
|
|||
node: '>=0.3.1'
|
||||
resolution:
|
||||
integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
|
||||
/es6-object-assign/1.1.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
|
||||
/escape-string-regexp/1.0.5:
|
||||
dev: false
|
||||
engines:
|
||||
|
@ -165,6 +187,20 @@ packages:
|
|||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
|
||||
/extend/3.0.2:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
/file-uri-to-path/1.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||
/file-url/2.0.2:
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha1-6VF4TXkJUSfTcTApqwY/QIGMoq4=
|
||||
/find-up/2.1.0:
|
||||
dependencies:
|
||||
locate-path: 2.0.0
|
||||
|
@ -177,6 +213,15 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
/ftp/0.3.10:
|
||||
dependencies:
|
||||
readable-stream: 1.1.14
|
||||
xregexp: 2.0.0
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=0.8.0'
|
||||
resolution:
|
||||
integrity: sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=
|
||||
/get-caller-file/1.0.3:
|
||||
dev: false
|
||||
resolution:
|
||||
|
@ -188,6 +233,17 @@ packages:
|
|||
resolution:
|
||||
integrity: sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||
tarball: 'http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz'
|
||||
/get-uri/2.0.2:
|
||||
dependencies:
|
||||
data-uri-to-buffer: 1.2.0
|
||||
debug: 2.6.9
|
||||
extend: 3.0.2
|
||||
file-uri-to-path: 1.0.0
|
||||
ftp: 0.3.10
|
||||
readable-stream: 2.3.6
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==
|
||||
/glob/7.1.2:
|
||||
dependencies:
|
||||
fs.realpath: 1.0.0
|
||||
|
@ -199,17 +255,12 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
|
||||
/glob/7.1.3:
|
||||
dependencies:
|
||||
fs.realpath: 1.0.0
|
||||
inflight: 1.0.6
|
||||
inherits: 2.0.3
|
||||
minimatch: 3.0.4
|
||||
once: 1.4.0
|
||||
path-is-absolute: 1.0.1
|
||||
/graceful-fs/4.1.11:
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=0.4.0'
|
||||
resolution:
|
||||
integrity: sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
|
||||
integrity: sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
|
||||
/growl/1.10.5:
|
||||
dev: false
|
||||
engines:
|
||||
|
@ -238,10 +289,6 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
/interpret/1.1.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=
|
||||
/invert-kv/1.0.0:
|
||||
dev: false
|
||||
engines:
|
||||
|
@ -268,6 +315,14 @@ packages:
|
|||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
/isarray/0.0.1:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
||||
/isarray/1.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
/isexe/2.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
|
@ -321,11 +376,6 @@ packages:
|
|||
resolution:
|
||||
integrity: sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
tarball: 'http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz'
|
||||
/minimist/1.2.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
tarball: 'http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz'
|
||||
/mkdirp/0.5.1:
|
||||
dependencies:
|
||||
minimist: 0.0.8
|
||||
|
@ -447,22 +497,52 @@ packages:
|
|||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
|
||||
/path-parse/1.0.6:
|
||||
/pify/2.3.0:
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
|
||||
/process-nextick-args/2.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
integrity: sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
|
||||
/proper-lockfile/2.0.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.1.11
|
||||
retry: 0.10.1
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=4.0.0'
|
||||
resolution:
|
||||
integrity: sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0=
|
||||
/pseudomap/1.0.2:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
/rechoir/0.6.2:
|
||||
/readable-stream/1.1.14:
|
||||
dependencies:
|
||||
resolve: 1.8.1
|
||||
core-util-is: 1.0.2
|
||||
inherits: 2.0.3
|
||||
isarray: 0.0.1
|
||||
string_decoder: 0.10.31
|
||||
dev: false
|
||||
engines:
|
||||
node: '>= 0.10'
|
||||
resolution:
|
||||
integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
|
||||
integrity: sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
|
||||
tarball: 'http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz'
|
||||
/readable-stream/2.3.6:
|
||||
dependencies:
|
||||
core-util-is: 1.0.2
|
||||
inherits: 2.0.3
|
||||
isarray: 1.0.0
|
||||
process-nextick-args: 2.0.0
|
||||
safe-buffer: 5.1.2
|
||||
string_decoder: 1.1.1
|
||||
util-deprecate: 1.0.2
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
tarball: 'http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz'
|
||||
/require-directory/2.1.1:
|
||||
dev: false
|
||||
engines:
|
||||
|
@ -473,12 +553,14 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
|
||||
/resolve/1.8.1:
|
||||
dependencies:
|
||||
path-parse: 1.0.6
|
||||
/retry/0.10.1:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==
|
||||
integrity: sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
|
||||
/safe-buffer/5.1.2:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
/semver/5.5.1:
|
||||
dev: false
|
||||
hasBin: true
|
||||
|
@ -502,26 +584,6 @@ packages:
|
|||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
|
||||
/shelljs/0.7.8:
|
||||
dependencies:
|
||||
glob: 7.1.3
|
||||
interpret: 1.1.0
|
||||
rechoir: 0.6.2
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=0.11.0'
|
||||
hasBin: true
|
||||
resolution:
|
||||
integrity: sha1-3svPh0sNHl+3LhSxZKloMEjprLM=
|
||||
/shx/0.2.2:
|
||||
dependencies:
|
||||
es6-object-assign: 1.1.0
|
||||
minimist: 1.2.0
|
||||
shelljs: 0.7.8
|
||||
dev: false
|
||||
hasBin: true
|
||||
resolution:
|
||||
integrity: sha1-CjBNAgsO3xMGrYFXDoDwNG31ijk=
|
||||
/signal-exit/3.0.2:
|
||||
dev: false
|
||||
resolution:
|
||||
|
@ -558,6 +620,16 @@ packages:
|
|||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||
/string_decoder/0.10.31:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
|
||||
/string_decoder/1.1.1:
|
||||
dependencies:
|
||||
safe-buffer: 5.1.2
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
/strip-ansi/3.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 2.1.1
|
||||
|
@ -575,6 +647,12 @@ packages:
|
|||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||
/strip-bom/3.0.0:
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
|
||||
/strip-eof/1.0.0:
|
||||
dev: false
|
||||
engines:
|
||||
|
@ -604,6 +682,14 @@ packages:
|
|||
hasBin: true
|
||||
resolution:
|
||||
integrity: sha512-Veu0w4dTc/9wlWNf2jeRInNodKlcdLgemvPsrNpfu5Pq39sgfFjvIIgTsvUHCoLBnMhPoUA+tFxsXjU6VexVRQ==
|
||||
/urijs/1.18.12:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-WlvUkocbQ+GYhi8zkcbecbGYq7YLSd2I3InxAfqeh6mWvWalBE7bISDHcAL3J7STrWFfizuJ709srHD+RuABPQ==
|
||||
/util-deprecate/1.0.2:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
/which-module/2.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
|
@ -629,6 +715,10 @@ packages:
|
|||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
/xregexp/2.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=
|
||||
/y18n/3.2.1:
|
||||
dev: false
|
||||
resolution:
|
||||
|
@ -661,14 +751,31 @@ packages:
|
|||
resolution:
|
||||
integrity: sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==
|
||||
tarball: 'http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz'
|
||||
'file:projects/async-io.tgz':
|
||||
dependencies:
|
||||
'@types/node': 10.11.3
|
||||
'@types/pify': 0.0.28
|
||||
file-url: 2.0.2
|
||||
get-uri: 2.0.2
|
||||
mocha: 5.2.0
|
||||
mocha-typescript: 1.1.17
|
||||
pify: 2.3.0
|
||||
proper-lockfile: 2.0.1
|
||||
strip-bom: 3.0.0
|
||||
typescript: 3.1.1
|
||||
urijs: 1.18.12
|
||||
dev: false
|
||||
name: '@rush-temp/async-io'
|
||||
resolution:
|
||||
integrity: sha512-i1azoeW0jx/VUDrCeWWBLTUK+NeH4VvW0JHp0OlTY82V84suqO0RV3kH+9s4zQ48R31QgEsu6X0MuBDOnGw6IQ==
|
||||
tarball: 'file:projects/async-io.tgz'
|
||||
version: 0.0.0
|
||||
'file:projects/tasks.tgz':
|
||||
dependencies:
|
||||
'@types/mocha': 5.2.5
|
||||
'@types/node': 10.11.3
|
||||
mocha: 5.2.0
|
||||
mocha-typescript: 1.1.17
|
||||
semver: 5.5.1
|
||||
shx: 0.2.2
|
||||
source-map-support: 0.5.9
|
||||
typescript: 3.1.1
|
||||
dev: false
|
||||
|
@ -681,10 +788,18 @@ registry: 'https://registry.npmjs.org/'
|
|||
shrinkwrapMinorVersion: 9
|
||||
shrinkwrapVersion: 3
|
||||
specifiers:
|
||||
'@rush-temp/async-io': 'file:./projects/async-io.tgz'
|
||||
'@rush-temp/tasks': 'file:./projects/tasks.tgz'
|
||||
'@types/mocha': 5.2.5
|
||||
'@types/node': 10.11.3
|
||||
'@types/pify': 0.0.28
|
||||
file-url: 2.0.2
|
||||
get-uri: ^2.0.1
|
||||
mocha: 5.2.0
|
||||
mocha-typescript: 1.1.17
|
||||
pify: ^2.3.0
|
||||
proper-lockfile: ^2.0.1
|
||||
source-map-support: 0.5.9
|
||||
strip-bom: 3.0.0
|
||||
typescript: ^3.1.1
|
||||
urijs: ~1.18.10
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
!dist/**/*
|
||||
test/
|
||||
dist/test/
|
||||
package/
|
||||
.npmignore
|
||||
tsconfig.json
|
||||
*.ts
|
||||
!*.d.ts
|
||||
*.tgz
|
||||
.vscode
|
||||
.scripts
|
|
@ -0,0 +1,18 @@
|
|||
# Project: @microsoft.azure/async-ic
|
||||
|
||||
This package contains common code for the developer tools for generating Azure SDKs.
|
||||
|
||||
Including:
|
||||
- AutoRest
|
||||
|
||||
|
||||
### Description
|
||||
Async IO wrappers
|
||||
|
||||
### Contents
|
||||
|
||||
----
|
||||
|
||||
# Contributing
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
|
@ -0,0 +1,185 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as promisify from "pify";
|
||||
import { OutstandingTaskAwaiter, Exception, Delay } from '@microsoft.azure/tasks'
|
||||
|
||||
export class PathNotFoundException extends Exception {
|
||||
constructor(path: string, public exitCode: number = 1) {
|
||||
super(`File '${path}' not found.`, exitCode);
|
||||
Object.setPrototypeOf(this, PathNotFoundException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class PathIsNotFileException extends Exception {
|
||||
constructor(path: string, public exitCode: number = 1) {
|
||||
super(`File '${path}' is not a file.`, exitCode);
|
||||
Object.setPrototypeOf(this, PathIsNotFileException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class PathIsNotDirectoryException extends Exception {
|
||||
constructor(path: string, public exitCode: number = 1) {
|
||||
super(`File '${path}' is not a directory.`, exitCode);
|
||||
Object.setPrototypeOf(this, PathIsNotFileException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class UnableToRemoveException extends Exception {
|
||||
constructor(path: string, public exitCode: number = 1) {
|
||||
super(`Unable to remove '${path}'.`, exitCode);
|
||||
Object.setPrototypeOf(this, UnableToRemoveException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnableToMakeDirectoryException extends Exception {
|
||||
constructor(path: string, public exitCode: number = 1) {
|
||||
super(`Unable to create directory '${path}'.`, exitCode);
|
||||
Object.setPrototypeOf(this, UnableToMakeDirectoryException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const exists: (path: string | Buffer) => Promise<boolean> = path => new Promise<boolean>((r, j) => fs.stat(path, (err: NodeJS.ErrnoException, stats: fs.Stats) => err ? r(false) : r(true)));
|
||||
export const readdir: (path: string | Buffer) => Promise<Array<string>> = promisify(fs.readdir);
|
||||
export const close: (fd: number) => Promise<void> = promisify(fs.close);
|
||||
|
||||
export const writeFile: (filename: string, content: string) => Promise<void> = (filename, content) => Promise.resolve(fs.writeFileSync(filename, content)); // for some reason writeFile only produced empty files
|
||||
export const lstat: (path: string | Buffer) => Promise<fs.Stats> = promisify(fs.lstat);
|
||||
|
||||
const fs_rmdir: (path: string | Buffer) => Promise<void> = promisify(fs.rmdir);
|
||||
const unlink: (path: string | Buffer) => Promise<void> = promisify(fs.unlink);
|
||||
const fs_mkdir: (path: string | Buffer) => Promise<void> = promisify(fs.mkdir);
|
||||
const fs_open: (path: string | Buffer, flags: string | number) => Promise<number> = promisify(fs.open);
|
||||
const fs_close: (fs: number) => Promise<void> = promisify(fs.close);
|
||||
|
||||
export async function mkdir(dirPath: string) {
|
||||
if (!await isDirectory(dirPath)) {
|
||||
const p = path.normalize(dirPath + "/");
|
||||
const parent = path.dirname(dirPath);
|
||||
if (! await isDirectory(parent)) {
|
||||
if (p != parent) {
|
||||
await mkdir(parent);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await fs_mkdir(p);
|
||||
} catch (e) {
|
||||
if (!await isDirectory(p)) {
|
||||
throw new UnableToMakeDirectoryException(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fs_readFile: (filename: string, encoding: string, ) => Promise<string> = promisify(fs.readFile);
|
||||
|
||||
export async function readFile(filename: string): Promise<string> {
|
||||
return fs_readFile(filename, "utf-8");
|
||||
}
|
||||
|
||||
export async function isDirectory(dirPath: string): Promise<boolean> {
|
||||
try {
|
||||
if (await exists(dirPath)) {
|
||||
return (await lstat(dirPath)).isDirectory();
|
||||
}
|
||||
} catch (e) {
|
||||
// don't throw!
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function isFile(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
if (await exists(filePath)) {
|
||||
return !(await lstat(filePath)).isDirectory();
|
||||
}
|
||||
} catch (e) {
|
||||
// don't throw!
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function rmdir(dirPath: string) {
|
||||
// if it's not there, do nothing.
|
||||
if (!await exists(dirPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//if it's not a directory, that's bad.
|
||||
if (!await isDirectory(dirPath)) {
|
||||
throw new PathIsNotDirectoryException(dirPath);
|
||||
}
|
||||
|
||||
// make sure this isn't the current directory.
|
||||
if (process.cwd() === path.normalize(dirPath)) {
|
||||
process.chdir(`${dirPath}/..`);
|
||||
}
|
||||
|
||||
// make sure the folder is empty first.
|
||||
const files = await readdir(dirPath);
|
||||
if (files.length) {
|
||||
const awaiter = new OutstandingTaskAwaiter();
|
||||
try {
|
||||
for (const file of files) {
|
||||
try {
|
||||
const p = path.join(dirPath, file);
|
||||
|
||||
if (await isDirectory(p)) {
|
||||
// folders are recursively rmdir'd
|
||||
awaiter.Await(rmdir(p));
|
||||
}
|
||||
else {
|
||||
// files and symlinks are unlink'd
|
||||
awaiter.Await(unlink(p).catch(() => { }));
|
||||
}
|
||||
} catch (e) {
|
||||
// uh... can't.. ok.
|
||||
}
|
||||
|
||||
}
|
||||
} finally {
|
||||
// after all the entries are done
|
||||
await awaiter.Wait();
|
||||
}
|
||||
}
|
||||
try {
|
||||
// if this fails for some reason, check if it's important.
|
||||
await fs_rmdir(dirPath);
|
||||
} catch (e) {
|
||||
// is it gone? that's all we really care about.
|
||||
if (await isDirectory(dirPath)) {
|
||||
// directory did not delete
|
||||
throw new UnableToRemoveException(dirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function rmFile(filePath: string) {
|
||||
// not there? no problem
|
||||
if (!exists(filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// not a file? that's not cool.
|
||||
if (await isDirectory(filePath)) {
|
||||
throw new PathIsNotFileException(filePath);
|
||||
}
|
||||
|
||||
try {
|
||||
// files and symlinks are unlink'd
|
||||
await unlink(filePath);
|
||||
} catch (e) {
|
||||
// is it gone? that's all we really care about.
|
||||
if (await exists(filePath)) {
|
||||
// directory did not delete
|
||||
throw new UnableToRemoveException(filePath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as promisify from "pify";
|
||||
import { OutstandingTaskAwaiter, Exception, Delay } from '@microsoft.azure/tasks'
|
||||
import { isFile } from "./file-io"
|
||||
const { lock, check, } = require("proper-lockfile")
|
||||
|
||||
const fs_open: (path: string | Buffer, flags: string | number) => Promise<number> = promisify(fs.open);
|
||||
|
||||
export class UnableToReadLockException extends Exception {
|
||||
constructor(path: string, public exitCode: number = 1) {
|
||||
super(`Unable to create read lock on '${path}'.`, exitCode);
|
||||
Object.setPrototypeOf(this, UnableToReadLockException.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export interface UnlockOptions {
|
||||
realpath?: boolean;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export interface CheckOptions extends UnlockOptions {
|
||||
stale?: number;
|
||||
}
|
||||
|
||||
export interface LockOptions extends CheckOptions {
|
||||
update?: number;
|
||||
retries?: number;
|
||||
}
|
||||
|
||||
export type release = () => Promise<void>;
|
||||
export type _release = () => void;
|
||||
|
||||
export class Lock {
|
||||
private static _exclusive: (path: string, options?: LockOptions) => Promise<_release> = promisify(lock);
|
||||
public static check: (path: string, options?: CheckOptions) => Promise<boolean> = promisify(check);
|
||||
|
||||
public static async exclusive(path: string, options?: LockOptions): Promise<release> {
|
||||
return promisify(await this._exclusive(path, options));
|
||||
}
|
||||
|
||||
public static async waitForExclusive(path: string, timeout: number = 5 * 60 * 1000): Promise<release | null> {
|
||||
let result: release | null = null;
|
||||
const expire = Date.now() + timeout;
|
||||
|
||||
do {
|
||||
try {
|
||||
result = await this.exclusive(path);
|
||||
} catch (e) {
|
||||
// no worries. Just wait a few seconds and see if we can get it.
|
||||
await Delay(3000);
|
||||
}
|
||||
} while (result == null && expire > Date.now())
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async read(path: string, options?: LockOptions): Promise<release> {
|
||||
// first try to create the file
|
||||
// it's ok if it fails
|
||||
options = options || {};
|
||||
options.delay = options.delay || 2000;
|
||||
options.retries = options.retries || 4;
|
||||
|
||||
const p = `${path}.lock`;
|
||||
|
||||
try {
|
||||
fs.writeFileSync(p, 'lockfile');
|
||||
} catch (e) {
|
||||
// no worries.
|
||||
}
|
||||
|
||||
// try to open the file for read
|
||||
try {
|
||||
if (await isFile(p)) {
|
||||
const fd = await fs_open(p, 'r');
|
||||
return async () => {
|
||||
fs.close(fd, (err) => { });
|
||||
try {
|
||||
fs.unlinkSync(p);
|
||||
} catch (E) {
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
if (options.retries) {
|
||||
await Delay(options.delay);
|
||||
options.retries--;
|
||||
return await this.read(path, options);
|
||||
}
|
||||
throw new UnableToReadLockException(path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export * from "./file-io"
|
||||
export * from "./lock"
|
||||
export * from "./uri"
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"name": "@microsoft.azure/async-io",
|
||||
"version": "2.0.7",
|
||||
"description": "Promisify'd asnyc wrappers (for Azure Open Source Projects)",
|
||||
"main": "./dist/main.js",
|
||||
"typings": "./dist/main.d.ts",
|
||||
"engines": {
|
||||
"node": ">=7.10.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Azure/perks.async-io.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p .",
|
||||
"prepare": "npm run build",
|
||||
"test": "npm run build && mocha dist/test",
|
||||
"testci": "npm run build && mocha dist/test"
|
||||
},
|
||||
"keywords": [
|
||||
"perks",
|
||||
"async",
|
||||
"autorest",
|
||||
"azure",
|
||||
"typescript"
|
||||
],
|
||||
"author": "Microsoft",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Azure/perks.async-io/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Azure/perks.async-io#readme",
|
||||
"readme": "https://github.com/Azure/perks.async-io/readme.md",
|
||||
"devDependencies": {
|
||||
"mocha-typescript": "1.1.17",
|
||||
"@types/mocha": "5.2.5",
|
||||
"@types/node": "10.11.3",
|
||||
"mocha": "5.2.0",
|
||||
"typescript": "^3.1.1",
|
||||
"@types/pify": "0.0.28"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft.azure/tasks": "2.0.27",
|
||||
"file-url": "2.0.2",
|
||||
"get-uri": "^2.0.1",
|
||||
"pify": "^2.3.0",
|
||||
"proper-lockfile": "^2.0.1",
|
||||
"strip-bom": "3.0.0",
|
||||
"urijs": "~1.18.10"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import * as Mocha from 'mocha';
|
||||
|
||||
declare type MochaDone = Mocha.Done;
|
|
@ -0,0 +1,35 @@
|
|||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as tasks from '@microsoft.azure/tasks'
|
||||
import * as assert from "assert";
|
||||
import * as asyncio from '../main'
|
||||
import * as os from 'os'
|
||||
|
||||
@suite class AsyncIO {
|
||||
|
||||
@test async "Does Pify'd exist work"() {
|
||||
assert.equal(await asyncio.exists(__filename), true);
|
||||
}
|
||||
|
||||
|
||||
@test async "mkdir"() {
|
||||
const tmpFolder = `${os.tmpdir()}/something/deep/deep/inside`;
|
||||
await asyncio.rmdir(`${os.tmpdir()}/something`);
|
||||
|
||||
await asyncio.mkdir(tmpFolder);
|
||||
assert.equal(await asyncio.isDirectory(tmpFolder), true, "Deep Directory created");
|
||||
|
||||
// making it again should not fail
|
||||
await asyncio.mkdir(tmpFolder);
|
||||
assert.equal(await asyncio.isDirectory(tmpFolder), true, "still there...");
|
||||
|
||||
await asyncio.rmdir(`${os.tmpdir()}/something`);
|
||||
assert.equal(await asyncio.isDirectory(tmpFolder), false, "removed ");
|
||||
|
||||
|
||||
await asyncio.rmdir(tmpFolder);
|
||||
assert.equal(await asyncio.isDirectory(tmpFolder), false, "no worries ");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
import * as asyncio from '../main'
|
||||
import * as os from 'os'
|
||||
// ensure
|
||||
|
||||
@suite class AsyncIO {
|
||||
|
||||
@test async "Locking simple file"() {
|
||||
const release = await asyncio.Lock.exclusive(__filename);
|
||||
|
||||
assert.equal(await asyncio.Lock.check(__filename), true);
|
||||
release();
|
||||
assert.equal(await asyncio.Lock.check(__filename), false);
|
||||
|
||||
}
|
||||
|
||||
@test async "Locking - does lock deny access"() {
|
||||
const release = await asyncio.Lock.exclusive(__filename);
|
||||
let threw = false;
|
||||
try {
|
||||
const release2 = await asyncio.Lock.exclusive(__filename);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
assert.equal(threw, true);
|
||||
|
||||
release();
|
||||
assert.equal(await asyncio.Lock.check(__filename), false);
|
||||
}
|
||||
|
||||
@test async "ReadLock simple file"() {
|
||||
|
||||
// it should be not locked now
|
||||
assert.equal(await asyncio.Lock.check(__filename), false);
|
||||
|
||||
const release1 = await asyncio.Lock.read(__filename);
|
||||
|
||||
const release2 = await asyncio.Lock.read(__filename);
|
||||
|
||||
const release3 = await asyncio.Lock.read(__filename);
|
||||
|
||||
// it should be locked now
|
||||
assert.equal(await asyncio.Lock.check(__filename), true);
|
||||
|
||||
let threw = false;
|
||||
try {
|
||||
// should fail getting write lock here.
|
||||
await asyncio.Lock.exclusive(__filename);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
assert.equal(threw, true);
|
||||
|
||||
|
||||
release1();
|
||||
release2();
|
||||
release3();
|
||||
|
||||
const release4 = await asyncio.Lock.exclusive(__filename);
|
||||
assert.equal(await asyncio.Lock.check(__filename), true);
|
||||
release4();
|
||||
assert.equal(await asyncio.Lock.check(__filename), false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"alwaysStrict": true,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"module": "commonjs",
|
||||
"noEmitOnError": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"noEmitHelpers": false,
|
||||
"target": "es2017",
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"lib": [
|
||||
"es2017"
|
||||
],
|
||||
"experimentalDecorators": true,
|
||||
"newLine": "LF"
|
||||
},
|
||||
"exclude": [
|
||||
"dist",
|
||||
"node_modules",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function IsUri(uri: string): boolean {
|
||||
return /^([a-z0-9+.-]+):(?:\/\/(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(?::(\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?|(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?$/i.test(uri);
|
||||
}
|
||||
|
||||
/***********************
|
||||
* Data aquisition
|
||||
***********************/
|
||||
import * as promisify from "pify";
|
||||
import { Readable } from "stream";
|
||||
import { parse } from "url";
|
||||
import { sep } from "path";
|
||||
|
||||
const stripBom: (text: string) => string = require("strip-bom");
|
||||
const getUri = require("get-uri");
|
||||
const getUriAsync: (uri: string) => Promise<Readable> = promisify(getUri);
|
||||
|
||||
/**
|
||||
* Loads a UTF8 string from given URI.
|
||||
*/
|
||||
export async function ReadUri(uri: string): Promise<string> {
|
||||
try {
|
||||
const readable = await getUriAsync(uri);
|
||||
|
||||
const readAll = new Promise<string>(function (resolve, reject) {
|
||||
let result = "";
|
||||
readable.on("data", data => result += data.toString());
|
||||
readable.on("end", () => resolve(result));
|
||||
readable.on("error", err => reject(err));
|
||||
});
|
||||
|
||||
let result = await readAll;
|
||||
// fix up UTF16le files
|
||||
if (result.charCodeAt(0) === 65533 && result.charCodeAt(1) === 65533) {
|
||||
result = Buffer.from(result.slice(2)).toString("utf16le");
|
||||
}
|
||||
return stripBom(result);
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to load '${uri}' (${e})`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function ExistsUri(uri: string): Promise<boolean> {
|
||||
try {
|
||||
await ReadUri(uri);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
* URI manipulation
|
||||
***********************/
|
||||
import { dirname } from "path";
|
||||
const URI = require("urijs");
|
||||
const fileUri: (path: string, options: { resolve: boolean }) => string = require("file-url");
|
||||
|
||||
|
||||
/**
|
||||
* remake of path.isAbsolute... because it's platform dependent:
|
||||
* Windows: C:\\... -> true /... -> true
|
||||
* Linux: C:\\... -> false /... -> true
|
||||
*/
|
||||
function isAbsolute(path: string): boolean {
|
||||
return !!path.match(/^([a-zA-Z]:)?(\/|\\)/);
|
||||
}
|
||||
|
||||
/**
|
||||
* determines what an absolute URI is for our purposes, consider:
|
||||
* - we had Ruby try to use "Azure::ARM::SQL" as a file name, so that should not be considered absolute
|
||||
* - we want simple, easily predictable semantics
|
||||
*/
|
||||
function isUriAbsolute(url: string): boolean {
|
||||
return /^[a-z]+:\/\//.test(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a 'file:///' URI from given absolute path.
|
||||
* Examples:
|
||||
* - "C:\swagger\storage.yaml" -> "file:///C:/swagger/storage.yaml"
|
||||
* - "/input/swagger.yaml" -> "file:///input/swagger.yaml"
|
||||
*/
|
||||
export function CreateFileOrFolderUri(absolutePath: string): string {
|
||||
if (!isAbsolute(absolutePath)) {
|
||||
throw new Error(`Can only create file URIs from absolute paths. Got '${absolutePath}'`);
|
||||
}
|
||||
let result = fileUri(absolutePath, { resolve: false });
|
||||
// handle UNCs
|
||||
if (absolutePath.startsWith("//") || absolutePath.startsWith("\\\\")) {
|
||||
result = result.replace(/^file:\/\/\/\//, "file://");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export function CreateFileUri(absolutePath: string): string {
|
||||
return EnsureIsFileUri(CreateFileOrFolderUri(absolutePath));
|
||||
}
|
||||
export function CreateFolderUri(absolutePath: string): string {
|
||||
return EnsureIsFolderUri(CreateFileOrFolderUri(absolutePath));
|
||||
}
|
||||
|
||||
export function EnsureIsFolderUri(uri: string): string {
|
||||
return EnsureIsFileUri(uri) + "/";
|
||||
}
|
||||
export function EnsureIsFileUri(uri: string): string {
|
||||
return uri.replace(/\/$/g, "");
|
||||
}
|
||||
|
||||
export function GetFilename(uri: string): string {
|
||||
return uri.split("/").reverse()[0].split("\\").reverse()[0];
|
||||
}
|
||||
|
||||
export function GetFilenameWithoutExtension(uri: string): string {
|
||||
const lastPart = GetFilename(uri);
|
||||
const ext = lastPart.indexOf(".") === -1 ? "" : lastPart.split(".").reverse()[0];
|
||||
return lastPart.substr(0, lastPart.length - ext.length - 1);
|
||||
}
|
||||
|
||||
export function ToRawDataUrl(uri: string): string {
|
||||
// special URI handlers
|
||||
// - GitHub
|
||||
if (uri.startsWith("https://github")) {
|
||||
uri = uri.replace(/^https?:\/\/(github.com)(\/[^\/]+\/[^\/]+\/)(blob|tree)\/(.*)/ig, "https://raw.githubusercontent.com$2$4");
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* The singularity of all resolving.
|
||||
* With URI as our one data type of truth, this method maps an absolute or relative path or URI to a URI using given base URI.
|
||||
* @param baseUri Absolute base URI
|
||||
* @param pathOrUri Relative/absolute path/URI
|
||||
* @returns Absolute URI
|
||||
*/
|
||||
export function ResolveUri(baseUri: string, pathOrUri: string): string {
|
||||
if (isAbsolute(pathOrUri)) {
|
||||
return CreateFileOrFolderUri(pathOrUri);
|
||||
}
|
||||
// known here: `pathOrUri` is eiher URI (relative or absolute) or relative path - which we can normalize to a relative URI
|
||||
pathOrUri = pathOrUri.replace(/\\/g, "/");
|
||||
// known here: `pathOrUri` is a URI (relative or absolute)
|
||||
if (isUriAbsolute(pathOrUri)) {
|
||||
return pathOrUri;
|
||||
}
|
||||
// known here: `pathOrUri` is a relative URI
|
||||
if (!baseUri) {
|
||||
throw new Error("'pathOrUri' was detected to be relative so 'baseUri' is required");
|
||||
}
|
||||
try {
|
||||
return new URI(pathOrUri).absoluteTo(baseUri).toString();
|
||||
} catch (e) {
|
||||
throw new Error(`Failed resolving '${pathOrUri}' against '${baseUri}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
export function ParentFolderUri(uri: string): string | null {
|
||||
// root?
|
||||
if (uri.endsWith("//")) {
|
||||
return null;
|
||||
}
|
||||
// folder? => cut away last "/"
|
||||
if (uri.endsWith("/")) {
|
||||
uri = uri.slice(0, uri.length - 1);
|
||||
}
|
||||
// cut away last component
|
||||
const compLen = uri.split("/").reverse()[0].length;
|
||||
return uri.slice(0, uri.length - compLen);
|
||||
}
|
||||
|
||||
export function MakeRelativeUri(baseUri: string, absoluteUri: string): string {
|
||||
return new URI(absoluteUri).relativeTo(baseUri).toString();
|
||||
}
|
||||
|
||||
/***********************
|
||||
* OS abstraction (writing files, enumerating files)
|
||||
***********************/
|
||||
import { readdir, mkdir, exists, writeFile } from "./file-io";
|
||||
import { lstatSync, unlinkSync, rmdirSync } from "fs";
|
||||
|
||||
function isAccessibleFile(localPath: string) {
|
||||
try {
|
||||
return lstatSync(localPath).isFile();
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function FileUriToLocalPath(fileUri: string): string {
|
||||
const uri = parse(fileUri);
|
||||
if (!fileUri.startsWith("file:///")) {
|
||||
throw new Error(!fileUri.startsWith("file://")
|
||||
? `Protocol '${uri.protocol}' not supported for writing.`
|
||||
: `UNC paths not supported for writing.`);
|
||||
}
|
||||
// convert to path
|
||||
let p = uri.path;
|
||||
if (p === undefined) {
|
||||
throw new Error(`Cannot write to '${uri}'. Path not found.`);
|
||||
}
|
||||
if (sep === "\\") {
|
||||
p = p.substr(p.startsWith("/") ? 1 : 0);
|
||||
p = p.replace(/\//g, "\\");
|
||||
}
|
||||
return decodeURI(p);
|
||||
}
|
||||
|
||||
export async function EnumerateFiles(folderUri: string, probeFiles: string[] = []): Promise<string[]> {
|
||||
const results = new Array<string>();
|
||||
folderUri = EnsureIsFolderUri(folderUri);
|
||||
if (folderUri.startsWith("file:")) {
|
||||
let files: string[] = [];
|
||||
try {
|
||||
files = await readdir(FileUriToLocalPath(folderUri));
|
||||
} catch (e) { }
|
||||
results.push(...files
|
||||
.map(f => ResolveUri(folderUri, f))
|
||||
.filter(f => isAccessibleFile(FileUriToLocalPath(f))));
|
||||
} else {
|
||||
for (const candid of probeFiles.map(f => ResolveUri(folderUri, f))) {
|
||||
if (await ExistsUri(candid)) {
|
||||
results.push(candid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async function CreateDirectoryFor(filePath: string): Promise<void> {
|
||||
var dir: string = dirname(filePath);
|
||||
if (!await exists(dir)) {
|
||||
await CreateDirectoryFor(dir);
|
||||
try {
|
||||
await mkdir(dir);
|
||||
} catch (e) {
|
||||
// mkdir throws if directory already exists - which happens occasionally due to race conditions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function WriteStringInternal(fileName: string, data: string): Promise<void> {
|
||||
await CreateDirectoryFor(fileName);
|
||||
await writeFile(fileName, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes string to local file system.
|
||||
* @param fileUri Target file uri.
|
||||
* @param data String to write (encoding: UTF8).
|
||||
*/
|
||||
export function WriteString(fileUri: string, data: string): Promise<void> {
|
||||
return WriteStringInternal(FileUriToLocalPath(fileUri), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a folder on the local file system.
|
||||
* @param folderUri Folder uri.
|
||||
*/
|
||||
export async function ClearFolder(folderUri: string): Promise<void> {
|
||||
const path = FileUriToLocalPath(folderUri);
|
||||
const deleteFolderRecursive = async (path: string) => {
|
||||
if (await exists(path)) {
|
||||
for (const file of await readdir(path)) {
|
||||
var curPath = path + "/" + file;
|
||||
if (lstatSync(curPath).isDirectory()) {
|
||||
await deleteFolderRecursive(curPath);
|
||||
} else {
|
||||
unlinkSync(curPath);
|
||||
}
|
||||
}
|
||||
rmdirSync(path);
|
||||
}
|
||||
};
|
||||
await deleteFolderRecursive(path);
|
||||
}
|
|
@ -257,6 +257,11 @@
|
|||
"projectFolder": "libraries/tasks",
|
||||
"reviewCategory": "production"
|
||||
},
|
||||
{
|
||||
"packageName": "@microsoft.azure/async-io",
|
||||
"projectFolder": "libraries/async-io",
|
||||
"reviewCategory": "production"
|
||||
}
|
||||
//
|
||||
// {
|
||||
// "packageName": "my-toolchain",
|
||||
|
|
Загрузка…
Ссылка в новой задаче