支持发布到仓库

This commit is contained in:
zqm
2025-12-12 11:39:06 +08:00
parent a33ff6cf4f
commit c5d9b5ee6d
3 changed files with 392 additions and 12 deletions

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -10,7 +11,13 @@ namespace JoyD.Windows.CS
/// </summary> /// </summary>
public static class Util public static class Util
{ {
// CRC16/XMODEM算法实现带起始位置和长度 /// <summary>
/// 使用CRC16/XMODEM算法计算字节数组的CRC16校验值
/// </summary>
/// <param name="data">要计算CRC16的数据字节数组</param>
/// <param name="startIndex">计算的起始位置索引</param>
/// <param name="length">要计算的字节长度</param>
/// <returns>计算得到的CRC16校验值</returns>
public static ushort CalculateCRC16(byte[] data, int startIndex, int length) public static ushort CalculateCRC16(byte[] data, int startIndex, int length)
{ {
ushort crc = 0; ushort crc = 0;
@@ -31,13 +38,22 @@ namespace JoyD.Windows.CS
// CRC32-MPEG2算法实现 /// <summary>
/// 使用CRC32-MPEG2算法计算字节数组的CRC32校验值
/// </summary>
/// <param name="data">要计算CRC32的数据字节数组</param>
/// <returns>计算得到的CRC32校验值</returns>
public static uint CalculateCRC32(byte[] data) public static uint CalculateCRC32(byte[] data)
{ {
return CalculateCRC32(0xFFFFFFFF, data); return CalculateCRC32(0xFFFFFFFF, data);
} }
// 支持增量计算的CRC32方法 /// <summary>
/// 支持增量计算的CRC32-MPEG2算法实现
/// </summary>
/// <param name="crc">初始CRC值用于增量计算</param>
/// <param name="data">要计算CRC32的数据字节数组</param>
/// <returns>计算得到的CRC32校验值</returns>
public static uint CalculateCRC32(uint crc, byte[] data) public static uint CalculateCRC32(uint crc, byte[] data)
{ {
uint polynomial = 0x04C11DB7; uint polynomial = 0x04C11DB7;
@@ -56,7 +72,14 @@ namespace JoyD.Windows.CS
return crc; return crc;
} }
// 计算文件的CRC32通过文件路径 /// <summary>
/// 通过文件路径计算文件的CRC32校验值
/// </summary>
/// <param name="filePath">文件的完整路径</param>
/// <returns>计算得到的CRC32校验值</returns>
/// <exception cref="ArgumentException">当文件路径为空或无效时抛出</exception>
/// <exception cref="FileNotFoundException">当指定路径的文件不存在时抛出</exception>
/// <exception cref="IOException">当文件读取失败时抛出</exception>
public static uint CalculateFileCRC32(string filePath) public static uint CalculateFileCRC32(string filePath)
{ {
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
@@ -65,7 +88,13 @@ namespace JoyD.Windows.CS
} }
} }
// 计算文件的CRC32通过已打开的文件流 /// <summary>
/// 通过已打开的文件流计算文件的CRC32校验值
/// </summary>
/// <param name="fs">已打开的文件流</param>
/// <returns>计算得到的CRC32校验值</returns>
/// <exception cref="ArgumentNullException">当文件流为null时抛出</exception>
/// <exception cref="IOException">当文件读取失败时抛出</exception>
public static uint CalculateCRC32(FileStream fs) public static uint CalculateCRC32(FileStream fs)
{ {
uint crc = 0xFFFFFFFF; uint crc = 0xFFFFFFFF;
@@ -105,19 +134,44 @@ namespace JoyD.Windows.CS
return crc; return crc;
} }
// byte[]转base64编码 /// <summary>
/// 将字节数组转换为Base64编码的字符串
/// </summary>
/// <param name="data">要转换的字节数组</param>
/// <returns>Base64编码的字符串</returns>
/// <exception cref="ArgumentNullException">当输入数据为null时抛出</exception>
public static string ByteArrayToBase64(byte[] data) public static string ByteArrayToBase64(byte[] data)
{ {
return Convert.ToBase64String(data); return Convert.ToBase64String(data);
} }
// base64转byte[]编码 /// <summary>
/// 将Base64编码的字符串转换为字节数组
/// </summary>
/// <param name="base64">Base64编码的字符串</param>
/// <returns>转换后的字节数组</returns>
/// <exception cref="ArgumentNullException">当输入字符串为null时抛出</exception>
/// <exception cref="FormatException">当输入字符串不是有效的Base64格式时抛出</exception>
public static byte[] Base64ToByteArray(string base64) public static byte[] Base64ToByteArray(string base64)
{ {
return Convert.FromBase64String(base64); return Convert.FromBase64String(base64);
} }
// 构建不含前缀的FTPC命令返回byte[],直接处理字节流) /// <summary>
/// 构建不含前缀的FTPC命令字节流
/// </summary>
/// <param name="command">命令字符ASCII编码</param>
/// <param name="parameters">命令参数,支持以下类型:
/// <list type="bullet">
/// <item><description>long: 24位大端序数据如filesize24或addr24</description></item>
/// <item><description>ushort: 16位大端序数据长度</description></item>
/// <item><description>uint: 32位大端序数据如CRC32值</description></item>
/// <item><description>string: ASCII编码的字符串参数</description></item>
/// <item><description>byte[]: 原始字节数组参数</description></item>
/// </list>
/// </param>
/// <returns>包含命令、参数和CRC16校验的完整字节数组</returns>
/// <exception cref="ArgumentException">当参数类型不支持时抛出</exception>
public static byte[] BuildRawFTPCommand(char command, params object[] parameters) public static byte[] BuildRawFTPCommand(char command, params object[] parameters)
{ {
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
@@ -205,7 +259,12 @@ namespace JoyD.Windows.CS
} }
} }
// 构建完整通信命令接受byte[]输入) /// <summary>
/// 构建完整的通信命令字符串
/// </summary>
/// <param name="rawFTPCommand">通过BuildRawFTPCommand方法构建的原始FTPC命令字节流</param>
/// <returns>完整的通信命令字符串格式为set(LFMGR: FTPC, "base64_encoded_command")</returns>
/// <exception cref="ArgumentNullException">当输入命令字节流为null时抛出</exception>
public static string BuildCommunicationCommand(byte[] rawFTPCommand) public static string BuildCommunicationCommand(byte[] rawFTPCommand)
{ {
string base64 = Convert.ToBase64String(rawFTPCommand); string base64 = Convert.ToBase64String(rawFTPCommand);

View File

@@ -8,7 +8,7 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>JoyD.Windows.CS</RootNamespace> <RootNamespace>JoyD.Windows.CS</RootNamespace>
<AssemblyName>Utils</AssemblyName> <AssemblyName>JoyD.Windows.CS.Utils</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
@@ -21,7 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Utils.xml</DocumentationFile> <DocumentationFile>bin\Debug\JoyD.Windows.CS.Utils.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>

View File

@@ -0,0 +1,321 @@
# 托普瑞控制库发布脚本 请在 chcp 65001下运行
# 配置参数 - 基本设置
$scriptDir = Get-Location
$output = Join-Path $scriptDir "Output"
$server = "http://47.111.181.23:8081/repository/nuget-releases/"
$key = "admin:admin"
$actualDllName = "JoyD.Windows.CS.Utils.dll"
$targetDllName = "Utils.dll"
# NuGet包元数据配置 - 在此处修改所有元数据
$packageId = "com.joyd.utils"
$version = "1.0.0.0"
$title = "通用工具库"
$authors = "曾庆明"
$owners = "JoyD Technology"
$description = "通用工具库,提供一些常用的工具函数和扩展方法"
$copyright = "Copyright 2025 JoyD Technology"
$tags = @("utils", "工具库")
$projectUrl = "https://github.com/joyd/utils"
$licenseUrl = "https://opensource.org/licenses/MIT"
$iconFileName = "Utils.ico"
$iconSourcePath = Join-Path $scriptDir $iconFileName
$iconUrl = "http://47.111.181.23:8081/repository/gradle/main/Utils.ico"
$releaseNotes = "初始版本发布"
# 其他设置
$nupkgFileName = "$packageId.$version.nupkg"
$nupkgFilePath = Join-Path $output $nupkgFileName
Write-Host "========== 工具库发布开始 =========="
# 创建输出目录
if (!(Test-Path $output)) {
New-Item -ItemType Directory -Path $output -Force | Out-Null
Write-Host "已创建输出目录: $output"
} else {
Write-Host "使用现有输出目录: $output"
}
# 清理之前的构建文件
Write-Host "清理之前的构建文件.."
if (Test-Path "$output\$actualDllName") { Remove-Item -Path "$output\$actualDllName" -Force }
if (Test-Path "$output\$targetDllName") { Remove-Item -Path "$output\$targetDllName" -Force }
if (Test-Path "$output\$nupkgFileName") { Remove-Item -Path "$output\$nupkgFileName" -Force }
if (Test-Path "$output\$packageId.nuspec") { Remove-Item -Path "$output\$packageId.nuspec" -Force }
# 构建项目
Write-Host "1. 正在构建项目..."
Write-Host "当前目录: $scriptDir"
dotnet build "$scriptDir\Utils\Utils.csproj" -c Release -o "$output"
if ($LASTEXITCODE -ne 0) {
Write-Host "错误: 构建失败!" -ForegroundColor Red
exit 1
}
# 验证DLL是否存在
if (!(Test-Path "$output\$actualDllName")) {
Write-Host "错误: 在输出目录中找不到$actualDllName!" -ForegroundColor Red
exit 1
}
# 复制DLL并重命名用于打包
Copy-Item -Path "$output\$actualDllName" -Destination "$output\$targetDllName" -Force
Write-Host "已将 $actualDllName 复制并重命名为$targetDllName 用于打包"
# 复制图标文件到输出目录
if (Test-Path $iconSourcePath) {
Copy-Item -Path $iconSourcePath -Destination (Join-Path $output $iconFileName) -Force
Write-Host "已复制图标文件到输出目录: $iconFileName"
} else {
Write-Host "警告: 图标文件 $iconSourcePath 不存在,将使用默认图标" -ForegroundColor Yellow
}
Write-Host "2. 准备打包文件..."
# 在Output目录创建NuGet.Config文件这样dotnet nuget push命令就能正确找到它
$localNugetConfigPath = Join-Path -Path $output -ChildPath "NuGet.Config"
# 创建包含全面配置的NuGet.Config文件
$nugetConfigContent = @"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="allowInsecureConnections" value="true" />
<add key="DefaultPushSource" value="$server" />
</config>
<packageSources>
<add key="JoyD-Private" value="$server" />
</packageSources>
<packageSourceMapping>
<packageSource key="JoyD-Private">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
<packageSourceCredentials>
<JoyD-Private>
<add key="Username" value="admin" />
<add key="Password" value="YWRtaW46YWRtaW4=" />
</JoyD-Private>
</packageSourceCredentials>
</configuration>
"@
# 设置配置文件
Set-Content -Path $localNugetConfigPath -Value $nugetConfigContent
Write-Host "已在Output目录设置NuGet.Config: $localNugetConfigPath"
# 创建一个简单的.csproj文件用于打包无需还原
$tempProjContent = @"
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
<PackageId>$packageId</PackageId>
<Version>$version</Version>
<Title>$title</Title>
<Authors>$authors</Authors>
<Owners>$owners</Owners>
<Description>$description</Description>
<Copyright>$copyright</Copyright>
<PackageTags>$tagsString</PackageTags>
<PackageProjectUrl>$projectUrl</PackageProjectUrl>
<PackageLicenseUrl>$licenseUrl</PackageLicenseUrl>
<PackageIcon>$iconFileName</PackageIcon>
<PackageIconUrl></PackageIconUrl>
<PackageReleaseNotes>$releaseNotes</PackageReleaseNotes>
<PackageOutputPath>.</PackageOutputPath>
<RestorePackagesConfig>true</RestorePackagesConfig>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IsPackable>true</IsPackable>
<NoBuild>true</NoBuild>
</PropertyGroup>
<ItemGroup>
<Content Include="$targetDllName" Pack="true" PackagePath="lib\net40\$targetDllName" />
<Content Include="$iconFileName" Pack="true" PackagePath="$iconFileName" />
</ItemGroup>
</Project>
"@
$tempProjPath = "$output\Temp.csproj"
Set-Content -Path $tempProjPath -Value $tempProjContent
# 在输出目录中创建包结构
Write-Host "3. 创建NuGet包.."
# 在输出目录中创建完整的nuspec文件
$nuspecPath = Join-Path $output "$packageId.nuspec"
# 将tags数组转换为空格分隔的字符串
$tagsString = $tags -join " "
$nuspecContent = @"
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>$packageId</id>
<version>$version</version>
<title>$title</title>
<authors>$authors</authors>
<owners>$owners</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description</description>
<releaseNotes>$releaseNotes</releaseNotes>
<copyright>$copyright</copyright>
<tags>$tagsString</tags>
<projectUrl>$projectUrl</projectUrl>
<licenseUrl>$licenseUrl</licenseUrl>
<icon>$iconFileName</icon>
<iconUrl>$iconUrl</iconUrl>
<!-- -->
<!-- <dependencies> -->
<!-- <group targetFramework=".NETFramework4.0"> -->
<!-- <dependency id="Newtonsoft.Json" version="13.0.1" /> -->
<!-- </group> -->
<!-- </dependencies> -->
</metadata>
<files>
<file src="$targetDllName" target="lib\net40\" />
<file src="$iconFileName" target="\" />
</files>
</package>
"@
Set-Content -Path $nuspecPath -Value $nuspecContent -Encoding UTF8
Write-Host "已创建nuspec文件: $nuspecPath"
# 手动创建nupkg包结构
Write-Host "创建包结构.."
$tempDir = Join-Path $output "temp_pkg"
# 确保临时目录存在
if (!(Test-Path $tempDir)) {
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
}
# 创建lib/net40子目录
$libDir = Join-Path $tempDir "lib\net40"
if (!(Test-Path $libDir)) {
New-Item -ItemType Directory -Path $libDir -Force | Out-Null
}
# 复制DLL到包结构中
$sourceDllPath = Join-Path $output $targetDllName
$destDllPath = Join-Path $libDir $targetDllName
Copy-Item -Path $sourceDllPath -Destination $destDllPath -Force
Write-Host "已复制$sourceDllPath$destDllPath"
# 复制图标文件到包结构根目录
$sourceIconPath = Join-Path $output $iconFileName
$destIconPath = Join-Path $tempDir $iconFileName
if (Test-Path $sourceIconPath) {
Copy-Item -Path $sourceIconPath -Destination $destIconPath -Force
Write-Host "已复制图标文件到包结构: $destIconPath"
} else {
Write-Host "警告: 在输出目录中找不到图标文件 $sourceIconPath" -ForegroundColor Yellow
}
# 创建[Content_Types].xml文件有效nupkg必需
$contentTypesPath = Join-Path $tempDir "[Content_Types].xml"
# 使用-LiteralPath参数避免方括号被解释为通配符
Set-Content -LiteralPath $contentTypesPath -Value "<?xml version='1.0' encoding='utf-8'?><Types xmlns='http://schemas.openxmlformats.org/package/2006/content-types'><Default Extension='dll' ContentType='application/octet-stream'/><Default Extension='xml' ContentType='application/xml'/><Default Extension='png' ContentType='image/png'/><Default Extension='ico' ContentType='image/x-icon'/></Types>"
Write-Host "已在 $contentTypesPath 创建[Content_Types].xml"
# 复制nuspec文件到包结构根目录
$sourceNuspecPath = Join-Path $output "$packageId.nuspec"
$destNuspecPath = Join-Path $tempDir "$packageId.nuspec"
if (Test-Path $sourceNuspecPath) {
Copy-Item -Path $sourceNuspecPath -Destination $destNuspecPath -Force
Write-Host "已复制nuspec文件到包结构: $destNuspecPath"
} else {
Write-Host "警告: 找不到nuspec文件 $sourceNuspecPath" -ForegroundColor Yellow
}
# 创建zip文件并将其重命名为nupkg
$zipPath = Join-Path $output "temp_manual.zip"
# 清理任何现有文件
if (Test-Path $zipPath) {
Remove-Item -Path $zipPath -Force
Write-Host "已移除现有的zip文件"
}
if (Test-Path $nupkgFilePath) {
Remove-Item -Path $nupkgFilePath -Force
Write-Host "已移除现有的nupkg文件"
}
Write-Host "$tempDir\* 创建zip归档到$zipPath..."
Compress-Archive -Path "$tempDir\*" -DestinationPath $zipPath -Force
if (Test-Path $zipPath) {
Write-Host "正在将$zipPath 重命名为 $nupkgFilePath..."
Rename-Item -Path $zipPath -NewName $nupkgFileName -Force
if (Test-Path $nupkgFilePath) {
$nupkgFile = Get-Item $nupkgFilePath
Write-Host "✅ 成功创建包: $($nupkgFile.FullName)"
Write-Host "包大小: $([math]::Round($nupkgFile.Length / 1KB, 2)) KB"
}
}
# 清理临时文件夹
Remove-Item -Path $tempDir -Recurse -Force
Write-Host "已清理临时文件夹"
# 检查包文件是否存在
if (Test-Path $nupkgFilePath) {
$nupkgFile = Get-Item $nupkgFilePath
Write-Host "找到包文件: $($nupkgFile.FullName)"
Write-Host "4. 正在发布包到仓库..."
# 使用curl直接发布到HTTP仓库
Write-Host "使用curl直接发布到HTTP仓库..."
# 构建curl命令
$curlCommand = "curl.exe -X PUT -u $key -F package=@$nupkgFilePath $server"
Write-Host "正在执行: $curlCommand"
# 执行curl命令使用curl.exe避免PowerShell别名冲突
& curl.exe -X PUT -u $key -F package=@$nupkgFilePath $server
if ($LASTEXITCODE -eq 0) {
Write-Host "✅ 成功: 包发布成功" -ForegroundColor Green
Write-Host "包ID: $packageId"
Write-Host "版本: $version"
Write-Host "标题: $title"
Write-Host "作者: $authors"
Write-Host "所有者: $owners"
Write-Host "描述: $description"
Write-Host "标签: $tagsString"
Write-Host "仓库: $server"
} else {
Write-Host "❌ 错误: 包创建成功但发布失败" -ForegroundColor Red
Write-Host "包文件位置: $($nupkgFile.FullName)"
Write-Host "
您可以尝试手动发布使用curl命令"
Write-Host "curl -X PUT -u admin:admin -F \"package=@$($nupkgFile.FullName)\" $server"
Write-Host "
或者直接在项目中使用创建的包文件"
}
} else {
Write-Host "❌ 错误: 未创建NuGet包" -ForegroundColor Red
Write-Host "请检查dotnet CLI是否正确配置"
Write-Host "您可以尝试使用Output目录中的文件手动创建包"
}
# 最终清理
Write-Host "正在执行最终清理.."
if (Test-Path "$output\Temp.csproj") {
Remove-Item -Path "$output\Temp.csproj" -Force
Write-Host "已移除Temp.csproj"
}
# 删除我们在Output目录创建的NuGet.Config文件
if (Test-Path $localNugetConfigPath) {
Remove-Item -Path $localNugetConfigPath -Force
Write-Host "已删除临时创建的NuGet.Config"
}
Write-Host "
发布过程完成"