Skip to content

Commit 2272ee8

Browse files
author
messica
committed
feat: update github ci,update source info handle logic
1 parent e02d71b commit 2272ee8

File tree

4 files changed

+175
-86
lines changed

4 files changed

+175
-86
lines changed

.github/workflows/build.yml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Verify all release targets build (no packaging). Run on push to main and on pull_request.
2+
name: Build (all targets)
3+
4+
on:
5+
push:
6+
branches: [main, master]
7+
pull_request:
8+
branches: [main, master]
9+
10+
env:
11+
BINARY_NAME: proxy-convert
12+
RUST_BACKTRACE: 1
13+
14+
jobs:
15+
build:
16+
name: Build ${{ matrix.target }}
17+
runs-on: ${{ matrix.os }}
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
include:
22+
- os: ubuntu-latest
23+
target: x86_64-unknown-linux-gnu
24+
- os: ubuntu-latest
25+
target: aarch64-unknown-linux-gnu
26+
- os: ubuntu-latest
27+
target: x86_64-unknown-linux-musl
28+
- os: macos-14
29+
target: x86_64-apple-darwin
30+
- os: macos-14
31+
target: aarch64-apple-darwin
32+
- os: windows-latest
33+
target: x86_64-pc-windows-msvc
34+
- os: windows-latest
35+
target: aarch64-pc-windows-msvc
36+
37+
steps:
38+
- uses: actions/checkout@v4
39+
40+
- name: Install Rust toolchain
41+
uses: dtolnay/rust-toolchain@stable
42+
with:
43+
targets: ${{ matrix.target }}
44+
45+
- name: Cache cargo
46+
uses: Swatinem/rust-cache@2
47+
with:
48+
key: ${{ matrix.target }}
49+
50+
- name: Install Linux deps (glibc cross)
51+
if: matrix.os == 'ubuntu-latest' && matrix.target == 'aarch64-unknown-linux-gnu'
52+
run: |
53+
sudo apt-get update
54+
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross
55+
56+
- name: Set env for Linux aarch64 cross
57+
if: matrix.os == 'ubuntu-latest' && matrix.target == 'aarch64-unknown-linux-gnu'
58+
run: |
59+
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
60+
echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV
61+
echo "AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar" >> $GITHUB_ENV
62+
63+
- name: Install musl (x86_64)
64+
if: matrix.os == 'ubuntu-latest' && matrix.target == 'x86_64-unknown-linux-musl'
65+
run: sudo apt-get update && sudo apt-get install -y musl-tools
66+
67+
- name: Build
68+
run: cargo build --release --target ${{ matrix.target }} --verbose
69+
70+
- name: Test binary
71+
shell: bash
72+
run: |
73+
if [ "${{ matrix.os }}" = "windows-latest" ]; then
74+
exe="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}.exe"
75+
else
76+
exe="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
77+
fi
78+
if [ -f "$exe" ]; then
79+
"$exe" --version
80+
else
81+
echo "Binary not found: $exe"
82+
exit 1
83+
fi

.github/workflows/release.yml

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,105 +5,109 @@ on:
55
tags:
66
- 'v*'
77

8+
env:
9+
BINARY_NAME: proxy-convert
10+
RUST_BACKTRACE: 1
11+
812
jobs:
913
build:
10-
name: Build on ${{ matrix.os }} - ${{ matrix.target }}
14+
name: Build ${{ matrix.target }}
1115
runs-on: ${{ matrix.os }}
1216
strategy:
17+
fail-fast: false
1318
matrix:
1419
include:
20+
# Linux glibc + musl static
1521
- os: ubuntu-latest
1622
target: x86_64-unknown-linux-gnu
17-
# - os: ubuntu-latest
18-
# target: aarch64-unknown-linux-gnu
19-
- os: macos-latest
23+
- os: ubuntu-latest
24+
target: aarch64-unknown-linux-gnu
25+
- os: ubuntu-latest
26+
target: x86_64-unknown-linux-musl
27+
# macOS
28+
- os: macos-14
2029
target: x86_64-apple-darwin
21-
- os: macos-latest
30+
- os: macos-14
2231
target: aarch64-apple-darwin
32+
# Windows
2333
- os: windows-latest
2434
target: x86_64-pc-windows-msvc
35+
- os: windows-latest
36+
target: aarch64-pc-windows-msvc
2537

2638
steps:
27-
- name: Checkout code
39+
- name: Checkout
2840
uses: actions/checkout@v4
2941

30-
- name: Install system dependencies (Ubuntu only)
31-
if: matrix.os == 'ubuntu-latest'
32-
run: |
33-
sudo apt-get update
34-
sudo apt-get install -y build-essential
35-
sudo apt-get install -y libssl-dev
36-
if [ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]; then
37-
sudo apt-get install -y gcc-aarch64-linux-gnu
38-
sudo apt-get install -y g++-aarch64-linux-gnu
39-
sudo apt-get install -y libc6-dev-arm64-cross
40-
fi
42+
- name: Install Rust toolchain
43+
uses: dtolnay/rust-toolchain@stable
44+
with:
45+
targets: ${{ matrix.target }}
46+
47+
- name: Cache cargo
48+
uses: Swatinem/rust-cache@2
49+
with:
50+
key: ${{ matrix.target }}
51+
shared-key: release
4152

42-
- name: Set up Rust
53+
- name: Install Linux deps (glibc cross)
54+
if: matrix.os == 'ubuntu-latest' && matrix.target == 'aarch64-unknown-linux-gnu'
4355
run: |
44-
rustup update stable
45-
rustup target add ${{ matrix.target }}
56+
sudo apt-get update
57+
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross
4658
47-
- name: Set environment variables for ARM cross-compilation (Ubuntu only)
59+
- name: Set env for Linux aarch64 cross (glibc)
4860
if: matrix.os == 'ubuntu-latest' && matrix.target == 'aarch64-unknown-linux-gnu'
4961
run: |
5062
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
5163
echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV
5264
echo "AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar" >> $GITHUB_ENV
53-
echo "RANLIB_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ranlib" >> $GITHUB_ENV
54-
echo "PKG_CONFIG_ALLOW_CROSS=1" >> $GITHUB_ENV
55-
echo "PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu" >> $GITHUB_ENV
5665
57-
- name: Build project
66+
- name: Install musl (Linux static, x86_64 only)
67+
if: matrix.os == 'ubuntu-latest' && matrix.target == 'x86_64-unknown-linux-musl'
68+
run: sudo apt-get update && sudo apt-get install -y musl-tools
69+
70+
- name: Build
5871
run: cargo build --release --target ${{ matrix.target }} --verbose
5972

6073
- name: Test binary
74+
shell: bash
6175
run: |
62-
if [ "${{ matrix.os }}" == "windows-latest" ]; then
63-
binary_path=$(find target/${{ matrix.target }}/release -maxdepth 1 -type f -name "*.exe" | head -n 1)
76+
if [ "${{ matrix.os }}" = "windows-latest" ]; then
77+
exe="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}.exe"
6478
else
65-
binary_path=$(find target/${{ matrix.target }}/release -maxdepth 1 -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \) | head -n 1)
79+
exe="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
6680
fi
67-
if [ -n "$binary_path" ]; then
68-
$binary_path --version
81+
if [ -f "$exe" ]; then
82+
"$exe" --version
6983
else
70-
echo "No executable binary found."
84+
echo "Binary not found: $exe"
7185
exit 1
7286
fi
73-
shell: bash
74-
env:
75-
RUST_BACKTRACE: 1
7687
77-
- name: Package binary
88+
- name: Package
7889
shell: bash
7990
run: |
80-
if [ "${{ matrix.os }}" == "windows-latest" ]; then
81-
binary_path=$(find target/${{ matrix.target }}/release -maxdepth 1 -type f -name "*.exe" | head -n 1)
82-
binary_name=$(basename "$binary_path")
83-
else
84-
binary_path=$(find target/${{ matrix.target }}/release -maxdepth 1 -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \) | head -n 1)
85-
binary_name=$(basename "$binary_path")
86-
fi
87-
mkdir -p ./release
88-
cp "$binary_path" release/"$binary_name"
89-
cd release
90-
if [ "${{ matrix.os }}" == "windows-latest" ]; then
91-
7z a "$binary_name-${{ matrix.target }}.zip" "$binary_name"
92-
echo "Packaged file: ./release/$binary_name-${{ matrix.target }}.zip"
91+
if [ "${{ matrix.os }}" = "windows-latest" ]; then
92+
exe="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}.exe"
93+
out="${{ env.BINARY_NAME }}-${{ matrix.target }}.zip"
94+
mkdir -p release
95+
cp "$exe" release/
96+
(cd release && 7z a "$out" "${{ env.BINARY_NAME }}.exe")
9397
else
94-
tar czvf "$binary_name-${{ matrix.target }}.tar.gz" "$binary_name"
95-
echo "Packaged file: ./release/$binary_name-${{ matrix.target }}.tar.gz"
98+
exe="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
99+
out="${{ env.BINARY_NAME }}-${{ matrix.target }}.tar.gz"
100+
mkdir -p release
101+
cp "$exe" release/
102+
(cd release && tar czvf "$out" "${{ env.BINARY_NAME }}")
96103
fi
97-
cd ..
98-
104+
echo "PACKAGE_PATH=release/$out" >> $GITHUB_ENV
105+
99106
- name: Upload artifact
100107
uses: actions/upload-artifact@v4
101108
with:
102109
name: ${{ matrix.target }}
103-
path: |
104-
release/*.zip
105-
release/*.tar.gz
106-
if-no-files-found: error
110+
path: ${{ env.PACKAGE_PATH }}
107111

108112
release:
109113
name: Create Release
@@ -113,13 +117,12 @@ jobs:
113117
contents: write
114118

115119
steps:
116-
- name: Download all artifacts
120+
- name: Download artifacts
117121
uses: actions/download-artifact@v4
118122
with:
119123
path: artifacts
120124

121125
- name: Create Release
122-
id: create_release
123126
uses: softprops/action-gh-release@v2
124127
env:
125128
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -129,5 +132,5 @@ jobs:
129132
draft: false
130133
prerelease: false
131134
files: |
132-
artifacts/**/*.zip
133-
artifacts/**/*.tar.gz
135+
artifacts/*/*.tar.gz
136+
artifacts/*/*.zip

src/commands/convert.rs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl ConvertCommand {
183183
raw
184184
))
185185
})?;
186-
let (base, query_str) = raw.split_at(pos);
186+
let (_base, query_str) = raw.split_at(pos);
187187
let query_str = query_str.trim_start_matches('?');
188188
let mut name: Option<String> = None;
189189
let mut type_param: Option<String> = None;
@@ -207,15 +207,11 @@ impl ConvertCommand {
207207
source_type_str
208208
))
209209
})?;
210-
let source = if base.starts_with("http://") || base.starts_with("https://") {
211-
raw.to_string()
212-
} else {
213-
base.to_string()
214-
};
210+
// Keep full string (path|url + all query params); type/name/flag are parsed out but remain in source
215211
Ok(SourceMeta {
216212
name: name.filter(|s| !s.is_empty()),
217213
source_type,
218-
source,
214+
source: raw.to_string(),
219215
format: None,
220216
flag,
221217
})
@@ -319,19 +315,23 @@ pub async fn handle_convert(
319315
.or_else(|| config.template.clone());
320316

321317
tracing::info!("Starting conversion");
322-
tracing::info!(
323-
"Input sources: {}",
324-
final_sources
325-
.iter()
326-
.map(|m| format!(
327-
"{}@{:?}@{}",
328-
m.name.as_deref().unwrap_or(""),
329-
m.source_type,
330-
m.source
331-
))
332-
.collect::<Vec<_>>()
333-
.join(", ")
334-
);
318+
for (i, m) in final_sources.iter().enumerate() {
319+
let type_str = match &m.source_type {
320+
SourceProtocol::Clash => "clash",
321+
SourceProtocol::SingBox => "singbox",
322+
SourceProtocol::V2Ray => "v2ray",
323+
};
324+
let name_str = m.name.as_deref().unwrap_or("(none)");
325+
let flag_str = m.flag.as_deref().unwrap_or("(default)");
326+
tracing::info!(
327+
"Input source [{}]: {} type={} name={} flag={}",
328+
i + 1,
329+
m.source,
330+
type_str,
331+
name_str,
332+
flag_str
333+
);
334+
}
335335
tracing::info!(
336336
"Template: {}",
337337
final_template.as_deref().unwrap_or("(default)")
@@ -372,11 +372,11 @@ mod tests {
372372

373373
#[test]
374374
fn test_parse_source_string_url_format() {
375-
// Path + type only
375+
// Path + type only; source keeps full string (all params)
376376
let m = ConvertCommand::parse_source_string("./config.yaml?type=clash").unwrap();
377377
assert_eq!(m.name, None);
378378
assert!(matches!(m.source_type, SourceProtocol::Clash));
379-
assert_eq!(m.source, "./config.yaml");
379+
assert_eq!(m.source, "./config.yaml?type=clash");
380380
assert_eq!(m.flag, None);
381381

382382
// URL + type, name, flag
@@ -392,16 +392,17 @@ mod tests {
392392
);
393393
assert_eq!(m.flag.as_deref(), Some("sing-box"));
394394

395-
// File path with space (Eternal Network style)
395+
// File path with space (Eternal Network style); source keeps full string
396396
let m = ConvertCommand::parse_source_string("examples/sources/Eternal Network?type=singbox")
397397
.unwrap();
398398
assert_eq!(m.name, None);
399399
assert!(matches!(m.source_type, SourceProtocol::SingBox));
400-
assert_eq!(m.source, "examples/sources/Eternal Network");
400+
assert_eq!(m.source, "examples/sources/Eternal Network?type=singbox");
401401

402-
// Empty name filtered out
402+
// Empty name filtered out; source keeps full string including other params
403403
let m = ConvertCommand::parse_source_string("./x?type=clash&name=").unwrap();
404404
assert_eq!(m.name, None);
405+
assert_eq!(m.source, "./x?type=clash&name=");
405406
}
406407

407408
#[test]

src/utils/source/loader.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ impl SourceLoader {
4949
Self::append_flag_to_url(source, &source_meta.source_type, source_meta.flag.as_deref());
5050
Self::load_from_url(&url_with_flag, config).await
5151
} else {
52-
Self::load_from_file(source)
52+
// File path: use only the part before ? (query params are kept in source string for reference)
53+
let path = source.find('?').map(|i| &source[..i]).unwrap_or(source.as_str());
54+
Self::load_from_file(path)
5355
}
5456
}
5557

0 commit comments

Comments
 (0)