/**
 * Copyright (c) 2020, 2021 Oracle and/or its affiliates.  All rights reserved.
 * This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
 */ import { existsSync , readFileSync } from "fs" ; export class ConfigFileReader { /**
     * Default location of the config file.
     */ public static DEFAULT_FILE_PATH : string = "~/.oci/config" ; /**
     * The fallback default location of the config file. If and only if the DEFAULT_FILE_PATH does not exist,
     * this fallback default location will be used.
     */ public static FALLBACK_DEFAULT_FILE_PATH : string = "~/.oraclebmc/config" ; static DEFAULT_PROFILE_NAME : string = "DEFAULT" ; param profile return throws static parseDefault ( profile ) { const envVarConfigFile = process . env . OCI_CONFIG_FILE ; const defaultExists = ConfigFileReader . fileExists ( ConfigFileReader . DEFAULT_FILE_PATH ) ; const fallbackExists = ConfigFileReader . fileExists ( ConfigFileReader . FALLBACK_DEFAULT_FILE_PATH ) ; let configFileFromEnvVarExists = false ; if ( envVarConfigFile ) { configFileFromEnvVarExists = ConfigFileReader . fileExists ( envVarConfigFile ) ; } if ( defaultExists ) { return ConfigFileReader . parseFileFromPath ( ConfigFileReader . DEFAULT_FILE_PATH , profile ) ; } else if ( configFileFromEnvVarExists ) { return ConfigFileReader . parseFileFromPath ( envVarConfigFile ! , profile ) ; } else if ( fallbackExists ) { return ConfigFileReader . parseFileFromPath ( ConfigFileReader . FALLBACK_DEFAULT_FILE_PATH , profile ) ; } throw new Error ( ` Can't load the default config from ${ ConfigFileReader . DEFAULT_FILE_PATH } or ${ ConfigFileReader . FALLBACK_DEFAULT_FILE_PATH } because it does not exists or its not a file.` ) ; } static expandUserHome ( path ) { if ( path . startsWith ( "~/" ) || path . startsWith ( "~\\" ) ) { return ( require ( "os" ) . homedir ( ) + ConfigFileReader . correctPath ( process . platform === "win32" , path . substring ( 1 ) ) ) ; } else { return path ; } } static correctPath ( isWindows , path ) { if ( isWindows ) { path = path . replace ( "/" , "\\" ) ; } return path ; } static fileExists ( filepath ) { return existsSync ( ConfigFileReader . expandUserHome ( filepath ) ) ; } static parseFileFromPath ( path , profile ) { if ( ConfigFileReader . fileExists ( path ) ) { const fileContent = readFileSync ( ConfigFileReader . expandUserHome ( path ) , "utf8" ) ; return ConfigFileReader . parse ( fileContent , profile ) ; } throw Error ( `File does not exists at ${ path }` ) ; } static parse ( fileContent , profile ) { const lines = fileContent . split ( "\n" ) . filter ( Boolean ) ; const accumulator = new ConfigAccumulator ( ) ; lines . forEach ( l => { accumulator . accept ( l ) ; } ) ; if ( ! accumulator . foundDefaultProfile ) { console . info ( "No DEFAULT profile was specified in the configuration" ) ; } if ( profile !== null && ! accumulator . configurationsByProfile . has ( profile ) ) { throw new Error ( "No profile named " + profile + " exists in the configuration file" ) ; } return new ConfigFile ( accumulator , profile ) ; } } export class ConfigFile { profile : string | null ; accumulator : ConfigAccumulator ; constructor ( acc , profile ) { this . accumulator = acc ; this . profile = profile ; } param key return public get ( key ) { if ( this . profile && this . accumulator . configurationsByProfile . get ( this . profile ) ! . has ( key ) ) { return this . accumulator . configurationsByProfile . get ( this . profile ) ! . get ( key ) ! ; } return this . accumulator . foundDefaultProfile ? this . accumulator . configurationsByProfile . get ( ConfigFileReader . DEFAULT_PROFILE_NAME ) ! . get ( key ) ! : null ; } public get profileCredentials ( ) : ConfigAccumulator { return this . accumulator ; } } export class ConfigAccumulator { configurationsByProfile = new Map < string , Map < string , string > > ( ) ; "currentProfile" : string ; "foundDefaultProfile" : boolean = false ; accept ( line ) { const trimmedLine = line . trim ( ) ; if ( ! trimmedLine ) { return ; } if ( trimmedLine . charAt ( 0 ) === "#" ) { return ; } if ( trimmedLine . charAt ( 0 ) === "[" && trimmedLine . charAt ( trimmedLine . length - 1 ) === "]" ) { this . currentProfile = trimmedLine . substring ( 1 , trimmedLine . length - 1 ) . trim ( ) ; if ( ! this . currentProfile ) { throw Error ( "Cannot have empty profile name: " + line ) ; } if ( this . currentProfile === ConfigFileReader . DEFAULT_PROFILE_NAME ) { this . foundDefaultProfile = true ; } if ( ! this . configurationsByProfile . has ( this . currentProfile ) ) { this . configurationsByProfile . set ( this . currentProfile , new Map < string , string > ( ) ) ; } return ; } const splitIndex = trimmedLine . indexOf ( "=" ) ; if ( splitIndex === - 1 ) { throw new Error ( "Found line with no key-value pair: " + line ) ; } const key = trimmedLine . substring ( 0 , splitIndex ) . trim ( ) ; const value = trimmedLine . substring ( splitIndex + 1 ) . trim ( ) ; if ( ! key ) { throw new Error ( "Found line with no key: " + line ) ; } if ( ! this . currentProfile ) { throw new Error ( "Config parse error, attempted to read configuration without specifying a profile: " + line ) ; } this . configurationsByProfile . get ( this . currentProfile ) ! . set ( key , value ) ; } }