@ -1,6 +1,4 @@
import exclusions from "./data/exclude.json" assert { type : "json" } ;
import { exec , ExecException } from "child_process" ;
import * as fs from "fs" ;
import { exec } from "child_process" ;
import { parseString } from "xml2js" ;
import { parseString } from "xml2js" ;
import {
import {
SVNList ,
SVNList ,
@ -8,32 +6,56 @@ import {
SVNProperties ,
SVNProperties ,
DirType ,
DirType ,
InternalComponent ,
InternalComponent ,
SvnResource ,
SVNCheckoutResponse ,
SVNCheckoutResult ,
} from "./types.js" ;
} from "./types.js" ;
import { parseExternals } from "./parser.js" ;
import { parseExternals } from "./parser.js" ;
import { getConfig } from "./ConfigurationManager.js" ;
function execShellCommand ( cmd : string ) {
function execShellCommand ( cmd : string ) : Promise < string > {
return new Promise ( ( resolve ) = > {
return new Promise ( ( resolve , reject ) = > {
exec ( cmd , { maxBuffer : 1024 * 500 } , ( error , stdout , stderr ) = > {
exec (
cmd ,
{ maxBuffer : 1024 * 500 } ,
( error : ExecException | null , stdout : string , stderr : string ) = > {
if ( error ) {
if ( error ) {
console . warn ( error ) ;
// Handle known errors
if (
error . message . includes ( "not a working copy" ) ||
error . message . includes ( "does not exist" ) ||
error . message . includes ( "None of the targets are working copies" )
) {
reject ( new Error ( "NotAWorkingCopy" ) ) ;
} else {
// Reject the promise with unknown errors
console . log ( "Unknown error occurred" , error ) ;
reject ( new Error ( "Unknown error occurred" ) ) ;
}
}
}
resolve ( stdout || stderr ) ;
resolve ( stdout || stderr ) ;
} ) ;
}
) ;
} ) ;
} ) ;
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function svnCmdWithResponse (
async function svnCmdWithResponse (
cmd : string ,
cmd : string ,
baseUrl : string ,
baseUrl? : string ,
url : string ,
url? : string ,
returnRaw = false
localPath? : string ,
returnXml = true
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) : Promise < any > {
) : Promise < any > {
return new Promise ( ( resolve , reject ) = > {
return new Promise ( ( resolve , reject ) = > {
const execCommand = ` svn ${ cmd } " ${ baseUrl } ${ url } " --xml ` ;
let execCommand = ` svn ${ cmd } ` ;
if ( baseUrl && url ) execCommand += ` " ${ baseUrl } ${ url } " ` ;
if ( localPath ) execCommand += ` " ${ localPath } " ` ;
if ( returnXml ) execCommand += ` --xml ` ;
execShellCommand ( execCommand )
execShellCommand ( execCommand )
. then ( ( svnCmdResponse ) = > {
. then ( ( svnCmdResponse ) = > {
if ( returnXml ) {
parseString (
parseString (
svnCmdResponse as SVNList | SVNProperties ,
svnCmdResponse as SVNList | SVNProperties ,
( err , result ) = > {
( err , result ) = > {
@ -41,15 +63,14 @@ async function svnCmdWithResponse(
reject ( err ) ;
reject ( err ) ;
return ;
return ;
}
}
if ( returnRaw ) {
resolve ( result ) ;
} else {
const json = JSON . stringify ( result ) ;
const json = JSON . stringify ( result ) ;
const svnCmdResponseJson = JSON . parse ( json ) ;
const svnCmdResponseJson = JSON . parse ( json ) ;
resolve ( svnCmdResponseJson ) ;
resolve ( svnCmdResponseJson ) ;
}
}
}
) ;
) ;
} else {
resolve ( svnCmdResponse ) ;
}
} )
} )
. catch ( ( error ) = > {
. catch ( ( error ) = > {
reject ( error ) ;
reject ( error ) ;
@ -57,16 +78,49 @@ async function svnCmdWithResponse(
} ) ;
} ) ;
}
}
export async function svnCheckout (
baseUrl : string ,
url : string ,
localPath : string
) : Promise < SVNCheckoutResponse > {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const svnCheckoutResponse : any = await svnCmdWithResponse (
"checkout" ,
baseUrl ,
url ,
localPath ,
false
) ;
// checkout
if ( svnCheckoutResponse . startsWith ( "A" ) ) {
const updateRows = svnCheckoutResponse . split ( /\r\n/ ) ;
const numberOfUpdates = updateRows . length - 3 ;
const revision = updateRows [ updateRows . length - 2 ] . match ( /\d+/ ) ? . [ 0 ] ;
return { numberOfUpdates , revision } ;
} else {
return { numberOfUpdates : 0 , revision : 0 } ;
}
} catch ( error ) {
console . log ( error ) ;
throw error ;
}
}
export async function svnList (
export async function svnList (
baseUrl : string ,
baseUrl : string ,
url : string
url : string
) : Promise < InternalComponent [ ] > {
) : Promise < InternalComponent [ ] > {
try {
try {
const svnListResponse : InternalComponent [ ] = await svnCmdWithResponse (
const config = getConfig ( ) ;
const exclusions = config . exclusions ;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const svnListResponse : any = await svnCmdWithResponse (
"list" ,
"list" ,
baseUrl ,
baseUrl ,
url ,
url ,
false
undefined ,
true
) ;
) ;
type arrayOfSVNList = {
type arrayOfSVNList = {
@ -77,11 +131,6 @@ export async function svnList(
( { name } : arrayOfSVNList ) = > ` ${ name [ 0 ] } `
( { name } : arrayOfSVNList ) = > ` ${ name [ 0 ] } `
) ;
) ;
const excludeJson = fs . readFileSync ( "./dist/data/exclude.json" , "utf-8" ) ;
const exclude = JSON . parse ( excludeJson ) ;
// const parsedExclusions = exclusions;
const filteredInternals = internals . filter (
const filteredInternals = internals . filter (
( internal : string ) = > ! exclusions . includes ( internal )
( internal : string ) = > ! exclusions . includes ( internal )
) ;
) ;
@ -93,6 +142,31 @@ export async function svnList(
}
}
}
}
export async function svnInfo (
// baseUrl: string,
// url: string,
localPath : string
) : Promise < SvnResource > {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const svnInfoResponse : any = await svnCmdWithResponse (
"info" ,
undefined ,
undefined ,
localPath ,
true
) ;
const fullUrl = svnInfoResponse . info . entry [ 0 ] . url [ 0 ] ;
const revision = svnInfoResponse . info . entry [ 0 ] . $ . revision ;
const returnObject : SvnResource = { fullUrl , revision } ;
return returnObject ;
} catch ( error ) {
console . log ( error ) ;
throw error ;
}
}
async function svnCmdWithoutResponse (
async function svnCmdWithoutResponse (
cmd : string ,
cmd : string ,
localPath : string
localPath : string
@ -102,7 +176,6 @@ async function svnCmdWithoutResponse(
const execCommand = ` svn ${ cmd } " ${ localPath } " ` ;
const execCommand = ` svn ${ cmd } " ${ localPath } " ` ;
execShellCommand ( execCommand )
execShellCommand ( execCommand )
. then ( ( svnCmdResponse ) = > {
. then ( ( svnCmdResponse ) = > {
console . log ( ` Performed ${ execCommand } ` ) ;
resolve ( svnCmdResponse ) ;
resolve ( svnCmdResponse ) ;
} )
} )
. catch ( ( error ) = > {
. catch ( ( error ) = > {
@ -111,16 +184,73 @@ async function svnCmdWithoutResponse(
} ) ;
} ) ;
}
}
export async function svnUpdate ( localPath : string ) : Promise < void > {
export async function svnUpdate ( localPath : string ) : Promise < boolean > {
try {
try {
await svnCmdWithoutResponse ( "cleanup" , localPath ) ;
await svnCmdWithoutResponse ( "cleanup" , localPath ) ;
const updateResponse = await svnCmdWithResponse (
"update" ,
undefined ,
undefined ,
localPath ,
false
) ;
return (
! updateResponse . includes ( "At revision" ) ||
updateResponse . includes ( "Updated to" )
) ;
} catch ( error ) {
} catch ( error ) {
console . log ( error ) ;
console . log ( "svnUpdateFailed" , error ) ;
throw new Error ( "svnUpdateFailed" ) ;
}
}
}
export async function svnSwitchWorkingCopy (
localPath : string ,
targetBaseUrl : string ,
targetUrl : string
) : Promise < boolean > {
try {
try {
await svnCmdWithoutResponse ( "update" , localPath ) ;
await svnCmdWithoutResponse ( "cleanup" , localPath ) ;
const switchResponse = await svnCmdWithResponse (
"switch" ,
targetBaseUrl ,
targetUrl ,
localPath ,
false
) ;
return (
switchResponse . includes ( "At revision" ) ||
switchResponse . includes ( "Updated to revision" )
) ;
} catch ( error ) {
} catch ( error ) {
console . log ( error ) ;
console . log ( "svnSwitchFailed" , error ) ;
throw new Error ( "svnSwitchFailed" ) ;
}
}
export async function svnSwitchExternal (
baseUrl : string ,
url : string ,
componentName : string , // in tortoise this is called Local path while editing svn:externals definitions
sourceUrl : string ,
targetUrl : string
) : Promise < boolean > {
try {
// get fresh raw externals
const propGetResult = await svnPropGet ( "svn:externals" , baseUrl , url ) ;
console . log ( propGetResult ) ;
// find
// if found
// propGetResult.replace()
// svmuc back as externals
//else throw error
const switchResponse = "" ;
return (
! switchResponse . includes ( "At revision" ) ||
switchResponse . includes ( "Updated to" )
) ;
} catch ( error ) {
console . log ( "svnSwitchFailed" , error ) ;
throw new Error ( "svnSwitchFailed" ) ;
}
}
}
}
@ -133,6 +263,7 @@ export async function svnPropGet(
` propget ${ property } ` ,
` propget ${ property } ` ,
baseUrl ,
baseUrl ,
url ,
url ,
undefined ,
true
true
) ;
) ;
const rawExternals : string =
const rawExternals : string =
@ -145,7 +276,7 @@ export async function svnTagsBranchesList(
baseUrl : string ,
baseUrl : string ,
url : string , // expects url that has tags and branches
url : string , // expects url that has tags and branches
latestOnly = false
latestOnly = false
) : Promise < string [ ] > {
) : Promise < string [ ] | undefined > {
try {
try {
url = url . replace ( /trunk$/ , "" ) ;
url = url . replace ( /trunk$/ , "" ) ;
url = url . replace ( /tags$/ , "" ) ;
url = url . replace ( /tags$/ , "" ) ;
@ -154,7 +285,9 @@ export async function svnTagsBranchesList(
const svnListResponse : SVNList = await svnCmdWithResponse (
const svnListResponse : SVNList = await svnCmdWithResponse (
"list" ,
"list" ,
baseUrl ,
baseUrl ,
url
url ,
undefined ,
true
) ;
) ;
const regex = /^[0-9.]+$/ ; // Regular expression for semantic version format
const regex = /^[0-9.]+$/ ; // Regular expression for semantic version format
type arrayOfSVNList = {
type arrayOfSVNList = {
@ -213,27 +346,27 @@ export async function svnTagsBranchesList(
export async function svnGetLatestTag (
export async function svnGetLatestTag (
baseUrl : string ,
baseUrl : string ,
url : string
url : string
) : Promise < string [ ] > {
) : Promise < string [ ] | undefined > {
return svnTagsBranchesList ( DirType . tags , baseUrl , url , true ) ;
return svnTagsBranchesList ( DirType . tags , baseUrl , url , true ) ;
}
}
export async function svnGetLatestBranch (
export async function svnGetLatestBranch (
baseUrl : string ,
baseUrl : string ,
url : string
url : string
) : Promise < string [ ] > {
) : Promise < string [ ] | undefined > {
return svnTagsBranchesList ( DirType . branches , baseUrl , url , true ) ;
return svnTagsBranchesList ( DirType . branches , baseUrl , url , true ) ;
}
}
export async function svnGetTagList (
export async function svnGetTagList (
baseUrl : string ,
baseUrl : string ,
url : string
url : string
) : Promise < string [ ] > {
) : Promise < string [ ] | undefined > {
return svnTagsBranchesList ( DirType . tags , baseUrl , url , false ) ;
return svnTagsBranchesList ( DirType . tags , baseUrl , url , false ) ;
}
}
export async function svnGetBranchesList (
export async function svnGetBranchesList (
baseUrl : string ,
baseUrl : string ,
url : string
url : string
) : Promise < string [ ] > {
) : Promise < string [ ] | undefined > {
return svnTagsBranchesList ( DirType . branches , baseUrl , url , false ) ;
return svnTagsBranchesList ( DirType . branches , baseUrl , url , false ) ;
}
}