Skip to content
This repository has been archived by the owner on Aug 31, 2021. It is now read-only.

Commit

Permalink
better handling of S3 config
Browse files Browse the repository at this point in the history
  • Loading branch information
mkloubert committed Dec 30, 2017
1 parent 6eabc27 commit 2bb88fa
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 10 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Change Log (vscode-deploy-reloaded)

## 0.10.0 (December 30th, 2017; shell commands)
## 0.10.0 (December 30th, 2017; shell commands and S3)

* added `executeOnStartup` [setting](https://github.com/mkloubert/vscode-deploy-reloaded/wiki#settings--), which runs [shell commands on startup](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/execute_on_startup)
* fixed use of [if](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/if) property in setting objects
* better handling of [credentials config](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_s3bucket#credentials) of [S3 target](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_s3bucket)

## 0.9.0 (December 30th, 2017; [Composer](https://getcomposer.org/))

Expand Down
182 changes: 173 additions & 9 deletions src/clients/s3bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import * as AWS from 'aws-sdk';
import * as deploy_clients from '../clients';
import * as deploy_files from '../files';
import * as deploy_helpers from '../helpers';
import * as deploy_values from '../values';
import * as Enumerable from 'node-enumerable';
import * as i18 from '../i18';
import * as MimeTypes from 'mime-types';
import * as OS from 'os';
import * as Path from 'path';
import * as Moment from 'moment';

Expand Down Expand Up @@ -61,11 +63,35 @@ export interface S3BucketOptions {
*/
readonly type?: string;
};
/**
* A custom function that provides scopes directories for relative paths.
*/
readonly directoryScopeProvider?: S3DirectoryScopeProvider;
/**
* A function that detects the ACL for a file
* when uploading it.
*/
readonly fileAcl?: S3BucketFileAclDetector;
/**
* A function that provides values for a client.
*/
readonly valueProvider?: S3ValueProvider;
}

/**
* A function that provides the scope directories for relative paths.
*/
export type S3DirectoryScopeProvider = () => string | string[] | PromiseLike<string | string[]>;

/**
* A function that provides values for use in settings for a client.
*/
export type S3ValueProvider = () => deploy_values.Value | deploy_values.Value[] | PromiseLike<deploy_values.Value | deploy_values.Value[]>;

interface SharedIniFileCredentialsOptions {
profile?: string
filename?: string
disableAssumeRole?: boolean
}


Expand Down Expand Up @@ -100,7 +126,86 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {
super();
}

private createInstance(): AWS.S3 {
private async createInstance(): Promise<AWS.S3> {
const AWS_DIR = Path.resolve(
Path.join(
OS.homedir(),
'.aws'
)
);

let directoryScopeProvider = this.options.directoryScopeProvider;
if (!directoryScopeProvider) {
directoryScopeProvider = () => [];
}

const DIRECTORY_SCOPES = Enumerable.from(
deploy_helpers.asArray(
await Promise.resolve( directoryScopeProvider() )
)
).select(s => {
return deploy_helpers.toStringSafe(s);
}).where(s => {
return !deploy_helpers.isEmptyString(s);
}).select(s => {
if (!Path.isAbsolute(s)) {
s = Path.join(AWS_DIR, s);
}

return Path.resolve(s);
}).toArray();

if (DIRECTORY_SCOPES.length < 1) {
DIRECTORY_SCOPES.push( AWS_DIR ); // .aws by default
}

let valueProvider = this.options.valueProvider;
if (!valueProvider) {
valueProvider = () => [];
}

const VALUES = deploy_helpers.asArray(
await Promise.resolve( valueProvider() )
);

const REPLACE_WITH_VALUES = (val: any) => {
return deploy_values.replaceWithValues(
VALUES,
val,
);
};

const FIND_FULL_FILE_PATH = async (p: string): Promise<string> => {
p = deploy_helpers.toStringSafe(p);

if (Path.isAbsolute(p)) {
// exist if file exists

if (await deploy_helpers.exists(p)) {
if ((await deploy_helpers.lstat(p)).isFile()) {
return Path.resolve(p); // file exists
}
}
}
else {
// detect existing, full path
for (const DS of DIRECTORY_SCOPES) {
let fullPath = REPLACE_WITH_VALUES(p);
fullPath = Path.join(DS, fullPath);
fullPath = Path.resolve(fullPath);

if (await deploy_helpers.exists(fullPath)) {
if ((await deploy_helpers.lstat(fullPath)).isFile()) {
return fullPath; // file found
}
}
}
}

throw new Error(i18.t('fileNotFound',
p));
};

let bucket = deploy_helpers.toStringSafe(this.options.bucket).trim();
if ('' === bucket) {
bucket = 'vscode-deploy-reloaded';
Expand All @@ -116,6 +221,65 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {
}

credentialConfig = this.options.credentials.config;

switch (credentialType) {
case 'environment':
// EnvironmentCredentials
if (!deploy_helpers.isNullOrUndefined(credentialConfig)) {
credentialConfig = REPLACE_WITH_VALUES(credentialConfig).trim();
}
break;

case 'file':
// FileSystemCredentials
if (!deploy_helpers.isNullOrUndefined(credentialConfig)) {
credentialConfig = deploy_helpers.toStringSafe(credentialConfig);

if (!deploy_helpers.isEmptyString(credentialConfig)) {
credentialConfig = await FIND_FULL_FILE_PATH(credentialConfig);
}
}
break;

case 'shared':
// SharedIniFileCredentials
{
const GET_PROFILE_SAFE = (profile: any): string => {
profile = deploy_helpers.toStringSafe(
REPLACE_WITH_VALUES(profile)
).trim();
if ('' === profile) {
profile = undefined;
}

return profile;
};

let sharedCfg: string | SharedIniFileCredentialsOptions = deploy_helpers.cloneObject(
credentialConfig
);
if (deploy_helpers.isObject<SharedIniFileCredentialsOptions>(sharedCfg)) {
sharedCfg.filename = deploy_helpers.toStringSafe(sharedCfg.filename);
}
else {
sharedCfg = {
profile: deploy_helpers.toStringSafe(sharedCfg),
};
}

if (deploy_helpers.isEmptyString(sharedCfg.filename)) {
sharedCfg.filename = undefined;
}
else {
sharedCfg.filename = await FIND_FULL_FILE_PATH(sharedCfg.filename);
}

sharedCfg.profile = GET_PROFILE_SAFE(sharedCfg.profile);

credentialConfig = sharedCfg;
}
break;
}
}

if (!credentialClass) {
Expand All @@ -138,11 +302,11 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {

path = toS3Path(path);

return new Promise<boolean>((resolve, reject) => {
return new Promise<boolean>(async (resolve, reject) => {
const COMPLETED = deploy_helpers.createCompletedAction(resolve, reject);

try {
const S3 = ME.createInstance();
const S3 = await ME.createInstance();

const PARAMS: any = {
Key: path,
Expand All @@ -169,11 +333,11 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {

path = toS3Path(path);

return new Promise<Buffer>((resolve, reject) => {
return new Promise<Buffer>(async (resolve, reject) => {
const COMPLETED = deploy_helpers.createCompletedAction(resolve, reject);

try {
const S3 = ME.createInstance();
const S3 = await ME.createInstance();

const PARAMS: any = {
Key: path,
Expand Down Expand Up @@ -208,7 +372,7 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {

path = toS3Path(path);

return new Promise<deploy_files.FileSystemInfo[]>((resolve, reject) => {
return new Promise<deploy_files.FileSystemInfo[]>(async (resolve, reject) => {
const COMPLETED = deploy_helpers.createCompletedAction(resolve, reject);

const ALL_OBJS: AWS.S3.Object[] = [];
Expand Down Expand Up @@ -280,7 +444,7 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {
};

try {
const S3 = ME.createInstance();
const S3 = await ME.createInstance();

let currentContinuationToken: string | false = false;

Expand Down Expand Up @@ -348,11 +512,11 @@ export class S3BucketClient extends deploy_clients.AsyncFileListBase {
data = Buffer.alloc(0);
}

return new Promise<void>((resolve, reject) => {
return new Promise<void>(async (resolve, reject) => {
const COMPLETED = deploy_helpers.createCompletedAction(resolve, reject);

try {
const S3 = ME.createInstance();
const S3 = await ME.createInstance();

let contentType = MimeTypes.lookup( Path.basename(path) );
if (false === contentType) {
Expand Down
1 change: 1 addition & 0 deletions src/i18.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export interface Translation {
initializing?: string;
};
file?: string;
fileNotFound?: string;
files?: string;
ftp?: {
couldNotConnect?: string;
Expand Down
1 change: 1 addition & 0 deletions src/lang/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const translation: Translation = {
initializing: "Erweiterung wird initialisiert ...",
},
file: "Datei",
fileNotFound: "Datei{0:trim,surround,leading_space} nicht gefunden!",
files: "Dateien",
ftp: {
couldNotConnect: "Konnte keine Verbindung aufbauen!",
Expand Down
1 change: 1 addition & 0 deletions src/lang/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const translation: Translation = {
initializing: "Extension is initializing ...",
},
file: "File",
fileNotFound: "File{0:trim,surround,leading_space} not found!",
files: "Files",
ftp: {
couldNotConnect: "Could not start connection!",
Expand Down
21 changes: 21 additions & 0 deletions src/plugins/s3bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import * as deploy_helpers from '../helpers';
import * as deploy_log from '../log';
import * as deploy_plugins from '../plugins';
import * as deploy_targets from '../targets';
import * as OS from 'os';
import * as Path from 'path';


interface S3BucketContext extends deploy_plugins.AsyncFileClientPluginContext<S3BucketTarget,
Expand Down Expand Up @@ -97,11 +99,27 @@ class S3BucketPlugin extends deploy_plugins.AsyncFileClientPluginBase<S3BucketTa
};
}

const SCOPES: string[] = [];
SCOPES.push
.apply(SCOPES,
target.__workspace.getSettingScopes());
SCOPES.push(
Path.resolve(
Path.join(
OS.homedir(),
'.aws'
)
)
);

return {
client: deploy_clients_s3bucket.createClient({
acl: ME.replaceWithValues(target, target.acl),
bucket: ME.replaceWithValues(target, target.bucket),
credentials: target.credentials,
directoryScopeProvider: () => {
return SCOPES;
},
fileAcl: (file, defAcl) => {
for (const ACL in FILTERS) {
if (deploy_helpers.checkIfDoesMatchByFileFilter('/' + file,
Expand All @@ -111,6 +129,9 @@ class S3BucketPlugin extends deploy_plugins.AsyncFileClientPluginBase<S3BucketTa
}

return defAcl;
},
valueProvider: () => {
return target.__workspace.getValues();
}
}),
getDir: (subDir) => {
Expand Down

0 comments on commit 2bb88fa

Please sign in to comment.