99using System . Collections . Generic ;
1010using System . IO ;
1111using System . Linq ;
12+ using System . Text . RegularExpressions ;
1213using System . Management . Automation ;
1314using System . Net ;
1415using System . Net . Http ;
@@ -440,12 +441,28 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe
440441 {
441442 ContainerRegistryServerAPICalls containerRegistryServer = new ContainerRegistryServerAPICalls ( repository , _cmdletPassedIn , _networkCredential , userAgentString ) ;
442443
443- var pkgMetadataFile = ( resourceType == ResourceType . Script ) ? pathToScriptFileToPublish : pathToModuleManifestToPublish ;
444+ if ( _isNupkgPathSpecified )
445+ {
446+ // copy the .nupkg to a temp path (outputNupkgDir field) as we don't want to tamper with the original, possibly signed, .nupkg file
447+ string copiedNupkgFilePath = CopyNupkgFileToTempPath ( nupkgFilePath : Path , errRecord : out ErrorRecord copyErrRecord ) ;
448+ if ( copyErrRecord != null )
449+ {
450+ _cmdletPassedIn . WriteError ( copyErrRecord ) ;
451+ return ;
452+ }
453+
454+ // get package info (name, version, metadata hashtable) from the copied .nupkg package and then populate appropriate fields (_pkgName, _pkgVersion, parsedMetadata)
455+ GetPackageInfoFromNupkg ( nupkgFilePath : copiedNupkgFilePath , errRecord : out ErrorRecord pkgInfoErrRecord ) ;
456+ if ( pkgInfoErrRecord != null )
457+ {
458+ _cmdletPassedIn . WriteError ( pkgInfoErrRecord ) ;
459+ return ;
460+ }
461+ }
444462
445- if ( ! containerRegistryServer . PushNupkgContainerRegistry ( pkgMetadataFile , outputNupkgDir , _pkgName , modulePrefix , _pkgVersion , resourceType , parsedMetadata , dependencies , out ErrorRecord pushNupkgContainerRegistryError ) )
463+ if ( ! containerRegistryServer . PushNupkgContainerRegistry ( outputNupkgDir , _pkgName , modulePrefix , _pkgVersion , resourceType , parsedMetadata , dependencies , _isNupkgPathSpecified , Path , out ErrorRecord pushNupkgContainerRegistryError ) )
446464 {
447465 _cmdletPassedIn . WriteError ( pushNupkgContainerRegistryError ) ;
448- // exit out of processing
449466 return ;
450467 }
451468 }
@@ -455,6 +472,7 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe
455472 {
456473 outputNupkgDir = pathToNupkgToPublish ;
457474 }
475+
458476 // This call does not throw any exceptions, but it will write unsuccessful responses to the console
459477 if ( ! PushNupkg ( outputNupkgDir , repository . Name , repository . Uri . ToString ( ) , out ErrorRecord pushNupkgError ) )
460478 {
@@ -474,7 +492,8 @@ internal void PushResource(string Repository, string modulePrefix, bool SkipDepe
474492 }
475493 finally
476494 {
477- if ( ! _isNupkgPathSpecified )
495+ // For scenarios such as Publish-PSResource -NupkgPath -Repository <non-container registry repository>, the outputNupkgDir will be set to NupkgPath path, and a temp outputDir folder will not have been created and thus doesn't need to attempt to be deleted
496+ if ( Directory . Exists ( outputDir ) )
478497 {
479498 _cmdletPassedIn . WriteVerbose ( string . Format ( "Deleting temporary directory '{0}'" , outputDir ) ) ;
480499 Utils . DeleteDirectory ( outputDir ) ;
@@ -1243,6 +1262,191 @@ private bool CheckDependenciesExist(Hashtable dependencies, string repositoryNam
12431262 return true ;
12441263 }
12451264
1265+ /// <summary>
1266+ /// This method is called by Publish-PSResource when the -NupkgPath parameter is specified
1267+ /// The method copies the .nupkg file to a temp path (populated at outputNupkgDir field) as we dont' want to extract and read original .nupkg file
1268+ /// </summary>
1269+ private string CopyNupkgFileToTempPath ( string nupkgFilePath , out ErrorRecord errRecord )
1270+ {
1271+ errRecord = null ;
1272+ string destinationFilePath = String . Empty ;
1273+ var packageFullName = System . IO . Path . GetFileName ( nupkgFilePath ) ;
1274+ try
1275+ {
1276+ if ( ! Directory . Exists ( outputDir ) )
1277+ {
1278+ Directory . CreateDirectory ( outputDir ) ;
1279+ if ( ! Directory . Exists ( outputNupkgDir ) )
1280+ {
1281+ Directory . CreateDirectory ( outputNupkgDir ) ;
1282+ }
1283+ }
1284+
1285+ destinationFilePath = System . IO . Path . Combine ( outputNupkgDir , packageFullName ) ;
1286+ File . Copy ( Path , destinationFilePath ) ;
1287+ }
1288+ catch ( Exception e )
1289+ {
1290+ errRecord = new ErrorRecord (
1291+ new ArgumentException ( $ "Error moving .nupkg at -NupkgPath to temp nupkg dir path '{ outputNupkgDir } ' due to: '{ e . Message } '.") ,
1292+ "ErrorMovingNupkg" ,
1293+ ErrorCategory . NotSpecified ,
1294+ this ) ;
1295+
1296+ // exit process record
1297+ return destinationFilePath ;
1298+ }
1299+
1300+ return destinationFilePath ;
1301+ }
1302+
1303+ /// <summary>
1304+ /// Get package info from the .nupkg file provided, inluding package name (_pkgName), package version (_pkgVersion), and metadata parsed into a hashtable (parsedMetadata)
1305+ /// </summary>
1306+ private void GetPackageInfoFromNupkg ( string nupkgFilePath , out ErrorRecord errRecord )
1307+ {
1308+ errRecord = null ;
1309+ Regex rx = new Regex ( @"\.\d+\." , RegexOptions . Compiled | RegexOptions . IgnoreCase ) ;
1310+ var packageFullName = System . IO . Path . GetFileName ( nupkgFilePath ) ;
1311+ MatchCollection matches = rx . Matches ( packageFullName ) ;
1312+ if ( matches . Count == 0 )
1313+ {
1314+ return ;
1315+ }
1316+
1317+ Match match = matches [ 0 ] ;
1318+
1319+ GroupCollection groups = match . Groups ;
1320+ if ( groups . Count == 0 )
1321+ {
1322+ return ;
1323+ }
1324+
1325+ Capture group = groups [ 0 ] ;
1326+
1327+ string pkgFoundName = packageFullName . Substring ( 0 , group . Index ) ;
1328+
1329+ string version = packageFullName . Substring ( group . Index + 1 , packageFullName . LastIndexOf ( '.' ) - group . Index - 1 ) ;
1330+ _cmdletPassedIn . WriteDebug ( $ "Found package '{ pkgFoundName } ', version '{ version } ', from packageFullName '{ packageFullName } ' at path '{ Path } '") ;
1331+
1332+ if ( ! NuGetVersion . TryParse ( version , out NuGetVersion nugetVersion ) )
1333+ {
1334+ errRecord = new ErrorRecord (
1335+ new ArgumentException ( $ "Error parsing version '{ version } ' into NuGetVersion instance.") ,
1336+ "ErrorParsingNuGetVersion" ,
1337+ ErrorCategory . NotSpecified ,
1338+ this ) ;
1339+
1340+ return ;
1341+ }
1342+
1343+ _pkgName = pkgFoundName ;
1344+ _pkgVersion = nugetVersion ;
1345+ parsedMetadata = GetMetadataFromNupkg ( nupkgFilePath , _pkgName , out errRecord ) ;
1346+ }
1347+
1348+ /// <summary>
1349+ /// Extract copied .nupkg, find metadata file (either .ps1, .psd1, or .nuspec) and read metadata into a hashtable
1350+ /// </summary>
1351+ internal Hashtable GetMetadataFromNupkg ( string copiedNupkgPath , string packageName , out ErrorRecord errRecord )
1352+ {
1353+ Hashtable pkgMetadata = new Hashtable ( StringComparer . OrdinalIgnoreCase ) ;
1354+ errRecord = null ;
1355+
1356+ // in temp directory create an "extract" folder to which we'll copy .nupkg to, extract contents, etc.
1357+ string nupkgDirPath = Directory . GetParent ( copiedNupkgPath ) . FullName ; //someGuid/nupkg/myPkg.nupkg -> /someGuid/nupkg
1358+ string tempPath = Directory . GetParent ( nupkgDirPath ) . FullName ; // someGuid
1359+ var extractPath = System . IO . Path . Combine ( tempPath , "extract" ) ; // someGuid/extract
1360+
1361+ try
1362+ {
1363+ var dir = Directory . CreateDirectory ( extractPath ) ;
1364+ dir . Attributes &= ~ FileAttributes . ReadOnly ;
1365+
1366+ // change extension to .zip
1367+ string zipFilePath = System . IO . Path . ChangeExtension ( copiedNupkgPath , ".zip" ) ;
1368+ File . Move ( copiedNupkgPath , zipFilePath ) ;
1369+
1370+ // extract from .zip
1371+ _cmdletPassedIn . WriteDebug ( $ "Extracting '{ zipFilePath } ' to '{ extractPath } '") ;
1372+ System . IO . Compression . ZipFile . ExtractToDirectory ( zipFilePath , extractPath ) ;
1373+
1374+ string psd1FilePath = String . Empty ;
1375+ string ps1FilePath = String . Empty ;
1376+ string nuspecFilePath = String . Empty ;
1377+ Utils . GetMetadataFilesFromPath ( extractPath , packageName , out psd1FilePath , out ps1FilePath , out nuspecFilePath , out string properCasingPkgName ) ;
1378+
1379+ List < string > pkgTags = new List < string > ( ) ;
1380+
1381+ if ( File . Exists ( psd1FilePath ) )
1382+ {
1383+ _cmdletPassedIn . WriteDebug ( $ "Attempting to read module manifest file '{ psd1FilePath } '") ;
1384+ if ( ! Utils . TryReadManifestFile ( psd1FilePath , out pkgMetadata , out Exception readManifestError ) )
1385+ {
1386+ errRecord = new ErrorRecord (
1387+ readManifestError ,
1388+ "GetMetadataFromNupkgFailure" ,
1389+ ErrorCategory . ParserError ,
1390+ this ) ;
1391+
1392+ return pkgMetadata ;
1393+ }
1394+ }
1395+ else if ( File . Exists ( ps1FilePath ) )
1396+ {
1397+ _cmdletPassedIn . WriteDebug ( $ "Attempting to read script file '{ ps1FilePath } '") ;
1398+ if ( ! PSScriptFileInfo . TryTestPSScriptFileInfo ( ps1FilePath , out PSScriptFileInfo parsedScript , out ErrorRecord [ ] errors , out string [ ] verboseMsgs ) )
1399+ {
1400+ errRecord = new ErrorRecord (
1401+ new InvalidDataException ( $ "PSScriptFile could not be read properly") ,
1402+ "GetMetadataFromNupkgFailure" ,
1403+ ErrorCategory . ParserError ,
1404+ this ) ;
1405+
1406+ return pkgMetadata ;
1407+ }
1408+
1409+ pkgMetadata = parsedScript . ToHashtable ( ) ;
1410+ }
1411+ else if ( File . Exists ( nuspecFilePath ) )
1412+ {
1413+ _cmdletPassedIn . WriteDebug ( $ "Attempting to read nuspec file '{ nuspecFilePath } '") ;
1414+ pkgMetadata = Utils . GetMetadataFromNuspec ( nuspecFilePath , _cmdletPassedIn , out errRecord ) ;
1415+ if ( errRecord != null )
1416+ {
1417+ return pkgMetadata ;
1418+ }
1419+ }
1420+ else
1421+ {
1422+ errRecord = new ErrorRecord (
1423+ new InvalidDataException ( $ ".nupkg package must contain either .psd1, .ps1, or .nuspec file and none were found") ,
1424+ "GetMetadataFromNupkgFailure" ,
1425+ ErrorCategory . InvalidData ,
1426+ this ) ;
1427+
1428+ return pkgMetadata ;
1429+ }
1430+ }
1431+ catch ( Exception e )
1432+ {
1433+ errRecord = new ErrorRecord (
1434+ new InvalidOperationException ( $ "Temporary folder for installation could not be created or set due to: { e . Message } ") ,
1435+ "GetMetadataFromNupkgFailure" ,
1436+ ErrorCategory . InvalidOperation ,
1437+ this ) ;
1438+ }
1439+ finally
1440+ {
1441+ if ( Directory . Exists ( extractPath ) )
1442+ {
1443+ Utils . DeleteDirectory ( extractPath ) ;
1444+ }
1445+ }
1446+
1447+ return pkgMetadata ;
1448+ }
1449+
12461450 #endregion
12471451 }
12481452}
0 commit comments