import * as path from "path" ; import { Logger } from "./logger" ; import { ByteWriter } from "./bytewriter" ; import { AsyncWriteStream } from "../../dal/asyncwritestream" ; import { CvsSupportProvider } from "../../dal/cvsprovider" ; import { CheckInInfo } from "../entities/checkininfo" ; import { CvsResource } from "../entities/cvsresources/cvsresource" ; import { ReadableSet } from "./readableset" ; import { inject , injectable } from "inversify" ; import { ReplacedCvsResource } from "../entities/cvsresources/replacedcvsresource" ; import { DeletedCvsResource } from "../entities/cvsresources/deletedcvsresource" ; import { Utils } from "./utils" ; import * as pify from "pify" ; import { TYPES } from "./constants" ; import { Settings } from "../entities/settings" ; import { GitProvider } from "../../dal/git/GitProvider" ; const temp = require ( "temp" ) . track ( ) ; @ injectable ( ) export class PatchManager { public constructor ( @ inject ( TYPES . Settings ) private readonly settings ) { } public async preparePatch ( checkInArray ) { if ( ! checkInArray && checkInArray . length === 0 ) { return ; } const patchBuilder = new PatchBuilder ( this . settings ) ; await patchBuilder . startPatching ( ) ; for ( let i = 0 ; i < checkInArray . length ; i ++ ) { const checkInInfo = checkInArray [ i ] ; await PatchManager . appendCheckInInfo ( patchBuilder , checkInInfo ) ; } return patchBuilder . finishPatching ( ) ; } private static async appendCheckInInfo ( patchBuilder , checkInInfo ) { const cvsProvider = checkInInfo . getCvsProvider ( ) ; const cvsResources = checkInInfo . cvsLocalResources ; for ( let i = 0 ; i < cvsResources . length ; i ++ ) { const cvsResource = cvsResources [ i ] ; await patchBuilder . appendCvsResource ( cvsProvider , cvsResource ) ; } } } class PatchBuilder { private static readonly END_OF_PATCH_MARK : number = 10 ; private writeSteam : AsyncWriteStream ; private patchAbsPath : string ; constructor ( private readonly settings ) { Logger . logDebug ( `PatchBuilder#constructor: start construct patch` ) ; } public async startPatching ( ) { Logger . logDebug ( `PatchBuilder#init: start construct patch` ) ; try { const dirPath = await pify ( temp . mkdir ) ( "VsCode_TeamCity" ) ; const inputPath = path . join ( dirPath , `.${ Utils . uuidv4 ( ) }.patch` ) ; this . patchAbsPath = inputPath ; this . writeSteam = new AsyncWriteStream ( inputPath ) ; Logger . logDebug ( `PatchBuilder#init: patchAbsPath is ${ inputPath }` ) ; } catch ( err ) { Logger . logError ( `PatchBuilder#init: an error occurs during making temp dir: ` + `${ Utils . formatErrorMessage ( err ) }` ) ; return Promise . reject ( err ) ; } } public async appendCvsResource ( cvsProvider , cvsResource ) { await this . appendHeaderForResource ( cvsResource ) ; await this . appendResourceContent ( cvsProvider , cvsResource ) ; if ( cvsResource instanceof ReplacedCvsResource ) { await this . appendReplacedFileAsRemoved ( cvsProvider , cvsResource ) ; } } private async appendHeaderForResource ( cvsResource ) { const header = cvsResource . getHeaderForPatch ( ) ; await this . writeSteam . write ( header ) ; } private async appendResourceContent ( cvsProvider , cvsResource ) { if ( cvsResource instanceof DeletedCvsResource ) { return ; } let fileContentStream ; if ( cvsProvider instanceof GitProvider && this . settings . shouldCollectGitChangesFromIndex ( ) ) { fileContentStream = await cvsProvider . getStagedFileContentStream ( cvsResource ) ; } else { fileContentStream = await cvsResource . getContentForPatch ( ) ; } if ( fileContentStream ) { await this . writeSteam . writeStreamedFile ( fileContentStream ) ; } } private async appendReplacedFileAsRemoved ( cvsProvider , cvsResource ) { const label = "" ; const removedResource = new DeletedCvsResource ( cvsResource . prevFileAbsPath , label , cvsResource . prevServerFilePath ) ; return this . appendCvsResource ( cvsProvider , removedResource ) ; } return public async finishPatching ( ) { try { await this . appendEofMark ( ) ; this . writeSteam . dispose ( ) ; } catch ( err ) { Logger . logError ( `CustomPatchSender#finishPatching: an error occurs ${ Utils . formatErrorMessage ( err ) }` ) ; } Logger . logInfo ( `CustomPatchSender#finishPatching: patch absPath is ${ this . patchAbsPath }` ) ; return this . patchAbsPath ; } private async appendEofMark ( ) { const emptyString = "" ; const byteEOPMark = ByteWriter . writeByte ( PatchBuilder . END_OF_PATCH_MARK ) ; const byteEmptyLine = ByteWriter . writeUTF ( emptyString ) ; await this . writeSteam . write ( Buffer . concat ( [ byteEOPMark , byteEmptyLine ] ) ) ; } }