@@ -2544,9 +2544,6 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
25442544exports . HashDiff = exports . fileHash = void 0 ;
25452545const fs_1 = __importDefault ( __nccwpck_require__ ( 5747 ) ) ;
25462546const crypto_1 = __importDefault ( __nccwpck_require__ ( 6417 ) ) ;
2547- function formatNumber ( number ) {
2548- return number . toLocaleString ( ) ;
2549- }
25502547function fileHash ( filename , algorithm ) {
25512548return __awaiter ( this , void 0 , void 0 , function * ( ) {
25522549return new Promise ( ( resolve , reject ) => {
@@ -2575,23 +2572,18 @@ function fileHash(filename, algorithm) {
25752572}
25762573exports . fileHash = fileHash ;
25772574class HashDiff {
2578- getDiffs ( localFiles , serverFiles , logger ) {
2575+ getDiffs ( localFiles , serverFiles ) {
25792576var _a , _b , _c ;
25802577const uploadList = [ ] ;
25812578const deleteList = [ ] ;
25822579const replaceList = [ ] ;
2580+ const sameList = [ ] ;
25832581let sizeUpload = 0 ;
25842582let sizeDelete = 0 ;
25852583let sizeReplace = 0 ;
25862584// alphabetize each list based off path
25872585const localFilesSorted = localFiles . data . sort ( ( first , second ) => first . name . localeCompare ( second . name ) ) ;
25882586const serverFilesSorted = serverFiles . data . sort ( ( first , second ) => first . name . localeCompare ( second . name ) ) ;
2589- logger . standard ( `----------------------------------------------------------------` ) ;
2590- logger . standard ( `Local Files:\t${ formatNumber ( localFilesSorted . length ) } ` ) ;
2591- logger . standard ( `Server Files:\t${ formatNumber ( localFilesSorted . length ) } ` ) ;
2592- logger . standard ( `----------------------------------------------------------------` ) ;
2593- logger . standard ( `Calculating differences between client & server` ) ;
2594- logger . standard ( `----------------------------------------------------------------` ) ;
25952587let localPosition = 0 ;
25962588let serverPosition = 0 ;
25972589while ( localPosition + serverPosition < localFilesSorted . length + serverFilesSorted . length ) {
@@ -2608,15 +2600,11 @@ class HashDiff {
26082600fileNameCompare = localFile . name . localeCompare ( serverFile . name ) ;
26092601}
26102602if ( fileNameCompare < 0 ) {
2611- let icon = localFile . type === "folder" ?`📁 Create` :`➕ Upload` ;
2612- logger . standard ( `${ icon } :${ localFile . name } ` ) ;
26132603uploadList . push ( localFile ) ;
26142604sizeUpload += ( _a = localFile . size ) !== null && _a !== void 0 ?_a :0 ;
26152605localPosition += 1 ;
26162606}
26172607else if ( fileNameCompare > 0 ) {
2618- let icon = serverFile . type === "folder" ?`📁` :`🗑️` ;
2619- logger . standard ( `${ icon } Delete:${ serverFile . name } ` ) ;
26202608deleteList . push ( serverFile ) ;
26212609sizeDelete += ( _b = serverFile . size ) !== null && _b !== void 0 ?_b :0 ;
26222610serverPosition += 1 ;
@@ -2625,10 +2613,9 @@ class HashDiff {
26252613// paths are a match
26262614if ( localFile . type === "file" && serverFile . type === "file" ) {
26272615if ( localFile . hash === serverFile . hash ) {
2628- logger . standard ( `⚖️ File content is the same, doing nothing: ${ localFile . name } ` ) ;
2616+ sameList . push ( localFile ) ;
26292617}
26302618else {
2631- logger . standard ( `🔁 File replace:${ localFile . name } ` ) ;
26322619sizeReplace += ( _c = localFile . size ) !== null && _c !== void 0 ?_c :0 ;
26332620replaceList . push ( localFile ) ;
26342621}
@@ -2637,10 +2624,26 @@ class HashDiff {
26372624serverPosition += 1 ;
26382625}
26392626}
2627+ // optimize modifications
2628+ let foldersToDelete = deleteList . filter ( ( item ) => item . type === "folder" ) ;
2629+ // remove files/folders that have a nested parent folder we plan on deleting
2630+ const optimizedDeleteList = deleteList . filter ( ( itemToDelete ) => {
2631+ const parentFolderIsBeingDeleted = foldersToDelete . find ( ( folder ) => {
2632+ const isSameFile = itemToDelete . name === folder . name ;
2633+ const parentFolderExists = itemToDelete . name . startsWith ( folder . name ) ;
2634+ return parentFolderExists && ! isSameFile ;
2635+ } ) !== undefined ;
2636+ if ( parentFolderIsBeingDeleted ) {
2637+ // a parent folder is being deleted, no need to delete this one
2638+ return false ;
2639+ }
2640+ return true ;
2641+ } ) ;
26402642return {
26412643upload :uploadList ,
2642- delete :deleteList ,
2644+ delete :optimizedDeleteList ,
26432645replace :replaceList ,
2646+ same :sameList ,
26442647 sizeDelete,
26452648 sizeReplace,
26462649 sizeUpload
@@ -2764,6 +2767,11 @@ function getServerFiles(client, logger, timings, args) {
27642767const serverFiles = yield downloadFileList ( client , logger , args [ "state-name" ] ) ;
27652768logger . all ( `----------------------------------------------------------------` ) ;
27662769logger . all ( `Last published on 📅${ new Date ( serverFiles . generatedTime ) . toLocaleDateString ( undefined , { weekday :"long" , year :"numeric" , month :"long" , day :"numeric" , hour :"numeric" , minute :"numeric" } ) } ` ) ;
2770+ // apply exclude options to server
2771+ if ( args . exclude . length > 0 ) {
2772+ const filteredData = serverFiles . data . filter ( ( item ) => utilities_1 . applyExcludeFilter ( { path :item . name , isDirectory :( ) => item . type === "folder" } , args . exclude ) ) ;
2773+ serverFiles . data = filteredData ;
2774+ }
27672775return serverFiles ;
27682776}
27692777catch ( error ) {
@@ -2810,7 +2818,33 @@ function deploy(args, logger, timings) {
28102818const serverFiles = yield getServerFiles ( client , logger , timings , args ) ;
28112819timings . start ( "logging" ) ;
28122820const diffTool = new HashDiff_1 . HashDiff ( ) ;
2813- const diffs = diffTool . getDiffs ( localFiles , serverFiles , logger ) ;
2821+ logger . standard ( `----------------------------------------------------------------` ) ;
2822+ logger . standard ( `Local Files:\t${ utilities_1 . formatNumber ( localFiles . data . length ) } ` ) ;
2823+ logger . standard ( `Server Files:\t${ utilities_1 . formatNumber ( serverFiles . data . length ) } ` ) ;
2824+ logger . standard ( `----------------------------------------------------------------` ) ;
2825+ logger . standard ( `Calculating differences between client & server` ) ;
2826+ logger . standard ( `----------------------------------------------------------------` ) ;
2827+ const diffs = diffTool . getDiffs ( localFiles , serverFiles ) ;
2828+ diffs . upload . filter ( ( itemUpload ) => itemUpload . type === "folder" ) . map ( ( itemUpload ) => {
2829+ logger . standard ( `📁 Create:${ itemUpload . name } ` ) ;
2830+ } ) ;
2831+ diffs . upload . filter ( ( itemUpload ) => itemUpload . type === "file" ) . map ( ( itemUpload ) => {
2832+ logger . standard ( `📄 Upload:${ itemUpload . name } ` ) ;
2833+ } ) ;
2834+ diffs . replace . map ( ( itemReplace ) => {
2835+ logger . standard ( `🔁 File replace:${ itemReplace . name } ` ) ;
2836+ } ) ;
2837+ diffs . delete . filter ( ( itemUpload ) => itemUpload . type === "file" ) . map ( ( itemDelete ) => {
2838+ logger . standard ( `📄 Delete:${ itemDelete . name } ` ) ;
2839+ } ) ;
2840+ diffs . delete . filter ( ( itemUpload ) => itemUpload . type === "folder" ) . map ( ( itemDelete ) => {
2841+ logger . standard ( `📁 Delete:${ itemDelete . name } ` ) ;
2842+ } ) ;
2843+ diffs . same . map ( ( itemSame ) => {
2844+ if ( itemSame . type === "file" ) {
2845+ logger . standard ( `⚖️ File content is the same, doing nothing:${ itemSame . name } ` ) ;
2846+ }
2847+ } ) ;
28142848timings . stop ( "logging" ) ;
28152849totalBytesUploaded = diffs . sizeUpload + diffs . sizeReplace ;
28162850timings . start ( "upload" ) ;
@@ -2835,7 +2869,7 @@ function deploy(args, logger, timings) {
28352869logger . all ( `----------------------------------------------------------------` ) ;
28362870logger . all ( `Time spent hashing:${ timings . getTimeFormatted ( "hash" ) } ` ) ;
28372871logger . all ( `Time spent connecting to server:${ timings . getTimeFormatted ( "connecting" ) } ` ) ;
2838- logger . all ( `Time spent deploying:${ timings . getTimeFormatted ( "upload" ) } (${ uploadSpeed } / second)` ) ;
2872+ logger . all ( `Time spent deploying:${ timings . getTimeFormatted ( "upload" ) } (${ uploadSpeed } / second)` ) ;
28392873logger . all ( ` - changing dirs:${ timings . getTimeFormatted ( "changingDir" ) } ` ) ;
28402874logger . all ( ` - logging:${ timings . getTimeFormatted ( "logging" ) } ` ) ;
28412875logger . all ( `----------------------------------------------------------------` ) ;
@@ -2927,26 +2961,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29272961return ( mod && mod . __esModule ) ?mod :{ "default" :mod } ;
29282962} ;
29292963Object . defineProperty ( exports , "__esModule" , ( { value :true } ) ) ;
2930- exports . getLocalFiles = exports . applyExcludeFilter = void 0 ;
2964+ exports . getLocalFiles = void 0 ;
29312965const readdir_enhanced_1 = __importDefault ( __nccwpck_require__ ( 8811 ) ) ;
29322966const types_1 = __nccwpck_require__ ( 6703 ) ;
29332967const HashDiff_1 = __nccwpck_require__ ( 9946 ) ;
2934- const multimatch_1 = __importDefault ( __nccwpck_require__ ( 8222 ) ) ;
2935- function applyExcludeFilter ( stat , excludeFilter ) {
2936- // match exclude, return immediatley
2937- if ( excludeFilter . length > 0 ) {
2938- const pathWithFolderSlash = stat . path + ( stat . isDirectory ( ) ?"/" :"" ) ;
2939- const excludeMatch = multimatch_1 . default ( pathWithFolderSlash , excludeFilter , { matchBase :true , dot :true } ) ;
2940- if ( excludeMatch . length > 0 ) {
2941- return false ;
2942- }
2943- }
2944- return true ;
2945- }
2946- exports . applyExcludeFilter = applyExcludeFilter ;
2968+ const utilities_1 = __nccwpck_require__ ( 4389 ) ;
29472969function getLocalFiles ( args ) {
29482970return __awaiter ( this , void 0 , void 0 , function * ( ) {
2949- const files = yield readdir_enhanced_1 . default . async ( args [ "local-dir" ] , { deep :true , stats :true , sep :"/" , filter :( stat ) => applyExcludeFilter ( stat , args . exclude ) } ) ;
2971+ const files = yield readdir_enhanced_1 . default . async ( args [ "local-dir" ] , { deep :true , stats :true , sep :"/" , filter :( stat ) => utilities_1 . applyExcludeFilter ( stat , args . exclude ) } ) ;
29502972const records = [ ] ;
29512973for ( let stat of files ) {
29522974if ( stat . isDirectory ( ) ) {
@@ -3138,22 +3160,12 @@ class FTPSyncProvider {
31383160} ) ;
31393161}
31403162removeFolder ( folderPath ) {
3141- var _a , _b ;
31423163return __awaiter ( this , void 0 , void 0 , function * ( ) {
3143- this . logger . all ( `removing folder "${ folderPath + "/" } "` ) ;
3144- const path = this . getFileBreadcrumbs ( folderPath + "/" ) ;
3145- if ( path . folders === null ) {
3146- this . logger . verbose ( ` no need to change dir` ) ;
3147- }
3148- else {
3149- const relativeFolderPath = path . folders [ ( ( _a = path . folders ) === null || _a === void 0 ?void 0 :_a . length ) - 1 ] + "/" ;
3150- this . logger . verbose ( ` removing folder "${ relativeFolderPath } "` ) ;
3151- if ( this . dryRun === false ) {
3152- yield utilities_1 . retryRequest ( this . logger , ( ) => __awaiter ( this , void 0 , void 0 , function * ( ) { return yield this . client . removeDir ( relativeFolderPath ) ; } ) ) ;
3153- }
3164+ const absoluteFolderPath = "/" + ( this . serverPath . startsWith ( "./" ) ?this . serverPath . replace ( "./" , "" ) :this . serverPath ) + folderPath ;
3165+ this . logger . all ( `removing folder "${ absoluteFolderPath } "` ) ;
3166+ if ( this . dryRun === false ) {
3167+ yield utilities_1 . retryRequest ( this . logger , ( ) => __awaiter ( this , void 0 , void 0 , function * ( ) { return yield this . client . removeDir ( absoluteFolderPath ) ; } ) ) ;
31543168}
3155- // navigate back to the root folder
3156- yield this . upDir ( ( _b = path . folders ) === null || _b === void 0 ?void 0 :_b . length ) ;
31573169this . logger . verbose ( ` completed` ) ;
31583170} ) ;
31593171}
@@ -3304,10 +3316,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33043316return ( mod && mod . __esModule ) ?mod :{ "default" :mod } ;
33053317} ;
33063318Object . defineProperty ( exports , "__esModule" , ( { value :true } ) ) ;
3307- exports . getDefaultSettings = exports . Timer = exports . Timings = exports . retryRequest = exports . pluralize = exports . Logger = void 0 ;
3319+ exports . applyExcludeFilter = exports . applyFolderFiltersToSubItems = exports . getDefaultSettings = exports . Timer = exports . Timings = exports . retryRequest = exports . formatNumber = exports . pluralize = exports . Logger = void 0 ;
33083320const pretty_ms_1 = __importDefault ( __nccwpck_require__ ( 1127 ) ) ;
33093321const module_1 = __nccwpck_require__ ( 8347 ) ;
33103322const types_1 = __nccwpck_require__ ( 6703 ) ;
3323+ const multimatch_1 = __importDefault ( __nccwpck_require__ ( 8222 ) ) ;
33113324class Logger {
33123325constructor ( level ) {
33133326this . level = level ;
@@ -3336,6 +3349,10 @@ function pluralize(count, singular, plural) {
33363349return plural ;
33373350}
33383351exports . pluralize = pluralize ;
3352+ function formatNumber ( number ) {
3353+ return number . toLocaleString ( ) ;
3354+ }
3355+ exports . formatNumber = formatNumber ;
33393356/**
33403357 * retry a request
33413358 *
@@ -3446,12 +3463,34 @@ function getDefaultSettings(withoutDefaults) {
34463463"state-name" :( _e = withoutDefaults [ "state-name" ] ) !== null && _e !== void 0 ?_e :".ftp-deploy-sync-state.json" ,
34473464"dry-run" :( _f = withoutDefaults [ "dry-run" ] ) !== null && _f !== void 0 ?_f :false ,
34483465"dangerous-clean-slate" :( _g = withoutDefaults [ "dangerous-clean-slate" ] ) !== null && _g !== void 0 ?_g :false ,
3449- "exclude" :( _h = withoutDefaults . exclude ) !== null && _h !== void 0 ?_h :module_1 . excludeDefaults ,
3466+ "exclude" :applyFolderFiltersToSubItems ( ( _h = withoutDefaults . exclude ) !== null && _h !== void 0 ?_h :module_1 . excludeDefaults ) ,
34503467"log-level" :( _j = withoutDefaults [ "log-level" ] ) !== null && _j !== void 0 ?_j :"standard" ,
34513468"security" :( _k = withoutDefaults . security ) !== null && _k !== void 0 ?_k :"loose" ,
34523469} ;
34533470}
34543471exports . getDefaultSettings = getDefaultSettings ;
3472+ /**
3473+ * automatically exclude all sub-files/sub-folders if we exclude a folder.
3474+ * For example "test/" should also exclude "test/file.txt"
3475+ * to do this we add "**" to all folder paths
3476+ */
3477+ function applyFolderFiltersToSubItems ( excludeFilters ) {
3478+ return excludeFilters . map ( filter => filter . endsWith ( "/" ) ?`${ filter } **` :filter ) ;
3479+ }
3480+ exports . applyFolderFiltersToSubItems = applyFolderFiltersToSubItems ;
3481+ function applyExcludeFilter ( stat , excludeFilters ) {
3482+ // match exclude, return immediatley
3483+ if ( excludeFilters . length > 0 ) {
3484+ // todo this could be a performance problem...
3485+ const pathWithFolderSlash = stat . path + ( stat . isDirectory ( ) ?"/" :"" ) ;
3486+ const excludeMatch = multimatch_1 . default ( pathWithFolderSlash , excludeFilters , { matchBase :true , dot :true } ) ;
3487+ if ( excludeMatch . length > 0 ) {
3488+ return false ;
3489+ }
3490+ }
3491+ return true ;
3492+ }
3493+ exports . applyExcludeFilter = applyExcludeFilter ;
34553494
34563495
34573496/***/ } ) ,
@@ -7957,9 +7996,6 @@ function optionalStringArray(argumentName, rawValue) {
79577996if ( typeof rawValue === "string" ) {
79587997throw new Error ( `${ argumentName } : invalid parameter - you provided "${ rawValue } ". This option expects an list in the EXACT format described in the readme` ) ;
79597998}
7960- if ( rawValue . length === 0 ) {
7961- return undefined ;
7962- }
79637999return rawValue ;
79648000}
79658001exports . optionalStringArray = optionalStringArray ;