@@ -2,8 +2,7 @@ import { basename, dirname, join } from "path"
22import { grantUserWriteAccess } from "admina"
33import { info , warning } from "ci-log"
44import { execa } from "execa"
5- import { mkdirp , move } from "fs-extra"
6- import { rm } from "fs/promises"
5+ import { mkdirp , move , readdir , remove , stat } from "fs-extra"
76import which from "which"
87import { setupSevenZip } from "../../sevenzip/sevenzip.js"
98import { setupTar } from "../../tar/tar.js"
@@ -50,7 +49,7 @@ export function getExtractFunction(archiveType: ArchiveType) {
5049 case ArchiveType . Tar :
5150 case ArchiveType . TarGz :
5251 case ArchiveType . TarXz :
53- return extractTarByExe
52+ return process . platform === "win32" ? extract7Zip : extractTarByExe
5453 case ArchiveType . Zip :
5554 return extractZip
5655 default :
@@ -61,23 +60,11 @@ export function getExtractFunction(archiveType: ArchiveType) {
6160let sevenZip : string | undefined
6261
6362/// Extract 7z using 7z
64- export async function extract7Zip ( file : string , dest : string ) {
63+ export async function extract7Zip ( file : string , dest : string , stripComponents : boolean = false ) {
6564 const name = basename ( file )
6665
6766 if ( / .* \. t a r \. .+ $ / . test ( name ) ) {
68- // if the file is tar.*, extract the compression first
69- const tarDir = dirname ( file )
70- await run7zip ( file , tarDir )
71- // extract the tar
72- const tarName = name . slice ( 0 , - 3 )
73- const tarFile = join ( tarDir , tarName )
74- await run7zip ( tarFile , tarDir )
75- await rm ( tarFile )
76- // Move the extracted files to the destination
77- const folderName = tarName . slice ( 0 , - 4 )
78- const folderPath = join ( tarDir , folderName )
79- info ( `Moving ${ folderPath } to ${ dest } ` )
80- await move ( folderPath , dest , { overwrite : true } )
67+ await extractTarXzBy7zip ( file , name , dest , stripComponents )
8168 } else {
8269 // extract the 7z file directly
8370 await run7zip ( file , dest )
@@ -86,6 +73,53 @@ export async function extract7Zip(file: string, dest: string) {
8673 return dest
8774}
8875
76+ async function extractTarXzBy7zip ( file : string , name : string , dest : string , stripComponents : boolean ) {
77+ if ( ! / .* \. t a r \. .+ $ / . test ( name ) ) {
78+ throw new Error ( `Invalid tar file: ${ name } ` )
79+ }
80+ // extract the compression first
81+ const tarDir = dirname ( file )
82+ await run7zip ( file , tarDir )
83+ // extract the tar
84+ const tarName = name . slice ( 0 , - 3 )
85+ const tarFile = join ( tarDir , tarName )
86+ await run7zip ( tarFile , tarDir )
87+ await remove ( tarFile )
88+ // move the extracted files to the destination
89+ const folderName = tarName . slice ( 0 , - 4 )
90+ const folderPath = join ( tarDir , folderName )
91+ info ( `Moving ${ folderPath } to ${ dest } ` )
92+ await move ( folderPath , dest , { overwrite : true } )
93+
94+ if ( stripComponents ) {
95+ await stripPathComponents ( dest , folderName )
96+ }
97+ }
98+
99+ async function stripPathComponents ( dest : string , folderName : string ) {
100+ // get all subfolders in the folder
101+ const subFolders = await readdir ( join ( dest , folderName ) )
102+ await Promise . all (
103+ subFolders . map ( async ( subFolder ) => {
104+ const subFolderPath = join ( dest , subFolder )
105+ if ( ! ( await stat ( subFolderPath ) ) . isDirectory ( ) ) {
106+ // if the subfolder is not a directory, do nothing
107+ return
108+ }
109+ // for each subfolder, move all files to the destination
110+ const subFiles = await readdir ( subFolderPath )
111+ await Promise . all (
112+ subFiles . map ( ( subFile ) => {
113+ return move ( join ( subFolderPath , subFile ) , join ( dest , subFile ) , { overwrite : true } )
114+ } ) ,
115+ )
116+ // remove the subfolder
117+ await remove ( subFolderPath )
118+ return
119+ } ) ,
120+ )
121+ }
122+
89123async function run7zip ( file : string , dest : string ) {
90124 info ( `7z: extracting ${ file } to ${ dest } ` )
91125 await execa ( await getSevenZip ( ) , [ "x" , file , `-o${ dest } ` , "-y" ] , { stdio : "inherit" } )
0 commit comments