Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/build-csharp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ jobs:
-p:Version=$VERSION \
-o artifacts/${{ matrix.prefix }}

- name: Build .Net (${{ matrix.target }})
if: matrix.target == 'windows'
shell: bash
run: |
VERSION="${{ steps.version.outputs.version }}"
dotnet publish \
src/Win \
-c Release \
-r ${{ matrix.rid }} \
-p:Version=$VERSION \
-o artifacts/${{ matrix.prefix }}

- name: Create setup-linux.zip
if: github.event_name != 'pull_request' && matrix.target == 'linux'
shell: bash
Expand All @@ -80,7 +92,8 @@ jobs:
run: |
Set-Location "artifacts/${{ matrix.prefix }}"
$items = @(
"appsettings.json"
"appsettings.json",
"anonymizerw.exe",
"Anonymizer.Core.dll",
"onnxruntime.dll",
"onnxruntime_providers_shared.dll")
Expand Down
1 change: 1 addition & 0 deletions Anonymizer.slnx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/Cli/Anonymizer.Cli.csproj" />
<Project Path="src/Win/Anonymizer.Win.csproj" />
</Folder>
</Solution>
54 changes: 17 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ It runs as a lightweight daemon on Windows and Linux, with a unified installer a
- Cross‑platform (Windows, Linux)
- Unified installer (Pwsh, Bash)
- Automatic OS detection
- Automatic service installation
- Automatic background start
- Self‑contained setup bundles (setup.zip)
- Semantic Versioning powered by git-cliff
- GitHub Actions automated release pipeline
Expand All @@ -35,13 +35,12 @@ curl -sL https://github.com/LsquaredTechnologies/Anonymizer/releases/latest/down
The installer will automatically:

- Detect Windows or Linux (WSL)
- Download win/setup.zip
- Extract it into %LOCALAPPDATA%/anonymizer
- Download setup.exe
- Copy it into %LOCALAPPDATA%/anonymizer
- Run:

```pwsh
setup.exe install anonymizer
setup.exe service install anonymizer
setup.exe install
```

### Linux
Expand All @@ -52,36 +51,23 @@ Bash
curl -sL https://github.com/LsquaredTechnologies/Anonymizer/releases/latest/download/install.sh | bash
```

Zsh

```zsh
curl -sL https://github.com/LsquaredTechnologies/Anonymizer/releases/latest/download/install.zsh | zsh
```

The installer will automatically:

- Detect Linux (including WSL)
- Download linux/setup.zip
- Extract it into ~/.local/share/anonymizer
- Download setup
- Copy it into ~/.local/share/anonymizer
- Run:

```shell
./anonymizer install anonymizer
./anonymizer service install anonymizer
./setup install
```

## 🛠️ Debugging

### Check service status

```shell
anonymizer status
```

### Run in foreground (debug mode)

```shell
anonymizer run --verbose
anonymizer run <pdf-file-or-directory>
```

### View logs
Expand All @@ -108,25 +94,23 @@ curl -sL https://github.com/LsquaredTechnologies/Anonymizer/releases/latest/down

The installer will automatically:

- Download the latest setup.zip
- Download the latest setup binary
- Replace binaries
- Restart the service
- Restart the background process

## ❌ Uninstalling

### Linux

```shell
anonymizer service uninstall
anonymizer uninstall
setup uninstall
rm -rf ~/.local/share/anonymizer
```

### Windows

```pwsh
setup.exe service uninstall anonymizer
setup.exe uninstall anonymizer
setup.exe uninstall
Remove-Item "$env:LOCALAPPDATA\anonymizer" -Recurse -Force
```

Expand All @@ -139,12 +123,8 @@ Remove-Item "$env:LOCALAPPDATA\anonymizer" -Recurse -Force
│ ├── install.ps1
│ └── install.sh
└── src/
└── Anonymizer.Cli/
└── scripts
├── anonymizer.py
├── download_model.py
├── downloader.py
└── face_detector.py
├── Anonymizer.Cli/
└── Anonymizer.Win/
```

## 🧪 Development
Expand All @@ -158,13 +138,13 @@ dotnet build
### Run

```shell
dotnet run --project src/Anonymizer
dotnet run --project src/Cli -- run <pdf-file-or-directory>
```

### Run service locally
### Run background watcher locally

```shell
dotnet run --project src/Anonymizer.Service
dotnet run --project src/Win
```

## 🚀 Release Workflow
Expand Down
17 changes: 9 additions & 8 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ $Repo = "Anonymizer"
Write-Host "Detecting OS..."
if ($PSVersionTable.OS -match "Linux") {
$OS = "linux"
$Suffix = ""
$InstallDir = "$HOME/.local/share/anonymizer"
$BinaryName = "setup"
$AnonName = Join-Path $InstallDir "anonymizer"
}
else {
$OS = "windows"
$Suffix = ".exe"
$InstallDir = Join-Path $env:LOCALAPPDATA "anonymizer"
$BinaryName = "setup.exe"
$AnonName = Join-Path $InstallDir "anonymizerw.exe"
}

if ($Version -eq "latest") {
Expand Down Expand Up @@ -53,8 +53,6 @@ if ($OS -eq "linux") {
chmod +x $FinalSetup
}

$AnonCmd = Join-Path $InstallDir ("anonymizer" + $Suffix)

$running = Get-Process | Where-Object { $_.ProcessName -like "anonymizer*" } 2>$null
if ($running) {
Write-Host "Stopping running instance..."
Expand All @@ -64,8 +62,11 @@ if ($running) {
Write-Host "Running installer..."
& $FinalSetup install

Write-Host "Downloading models..."
& $FinalSetup download

Write-Host "Launching Anonymizer..."
Start-Process $AnonCmd -ArgumentList "start" -WindowStyle Hidden
if ($OS -eq "windows") {
Start-Process "cmd.exe" -ArgumentList "/c start `"`" /b anonymizerw"
}
else {
chmod +x $AnonName
Start-Process $AnonName -ArgumentList "start" -WindowStyle Hidden
}
13 changes: 7 additions & 6 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ VERSION="${1:-latest}"
OWNER="LsquaredTechnologies"
REPO="Anonymizer"

echo "🔍 Detecting OS: $OS"
echo "🔍 Detecting OS..."
UNAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
case "$UNAME" in
linux*)
Expand All @@ -19,7 +19,7 @@ case "$UNAME" in
OS="windows"
INSTALL_DIR="${LOCALAPPDATA}/anonymizer"
BINARY_NAME="setup.exe"
ANON_NAME="anonymizer.exe"
ANON_NAME="anonymizerw.exe"
;;
*)
echo "❌ Unsupported OS: $UNAME"
Expand Down Expand Up @@ -58,8 +58,9 @@ fi
echo "⚙️ Running installer..."
"$SETUP" install

echo "📥 Downloading models..."
"$SETUP" download

echo "🚀 Launching Anonymizer..."
nohup "$ANON" start >/dev/null 2>&1 &
if [ "$OS" = "windows" ]; then
nohup "$ANON" >/dev/null 2>&1 &
else
nohup "$ANON" start >/dev/null 2>&1 &
fi
16 changes: 14 additions & 2 deletions src/Cli/Anonymizer.Cli.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<AssemblyName>anonymizer</AssemblyName>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>Anonymizer.Cli</RootNamespace>
<RootNamespace>Anonymizer</RootNamespace>
</PropertyGroup>

<PropertyGroup Label="AOT">
Expand All @@ -22,6 +22,18 @@
<TrimMode>full</TrimMode>
</PropertyGroup>

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'win-x64'">
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'">
<DefineConstants>$(DefineConstants);LINUX</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(RuntimeIdentifier)' != 'linux-x64'">
<Compile Remove="Commands/StartCommand.Linux.cs" />
</ItemGroup>

<ItemGroup Condition="'$(RuntimeIdentifier)' != 'linux-x64'">
<None Include="../Core/target/release/Anonymizer.Core.dll"
Condition="Exists('../Core/target/release/Anonymizer.Core.dll')">
Expand Down
6 changes: 2 additions & 4 deletions src/Cli/AnonymizerService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using Anonymizer.Cli.Core;
using Anonymizer.Core;

using Microsoft.Extensions.Logging;

namespace Anonymizer.Cli;
namespace Anonymizer;

internal sealed partial class AnonymizerService(ILogger<AnonymizerService> logger)
{
Expand Down Expand Up @@ -49,7 +49,6 @@ private async Task RunPipeline(FileInfo file, CancellationToken cancellationToke
OutputPaths output = OutputPaths.From(file);
await Task.Run(() =>
{
Console.WriteLine("[DEBUG] Avant RunPipeline()");
var result = NativeMethods.RedactPdf(file.FullName, ResolveModelsDirectory().FullName, output.AnonymizedPdfPath);
var error = result switch
{
Expand All @@ -64,7 +63,6 @@ await Task.Run(() =>
LogProcessError(file.FullName, error);
else
LogProcessTerminated(file.FullName);
Console.WriteLine("[DEBUG] Après RunPipeline()");
}, cancellationToken).ConfigureAwait(false);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Cli/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using static System.IO.Path;

namespace Anonymizer.Cli;
namespace Anonymizer;

internal static class Application
{
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/Commands/ConfigCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Microsoft.Extensions.Hosting;

namespace Anonymizer.Cli.Commands;
namespace Anonymizer.Commands;

internal sealed class ConfigCommand : Command
{
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/Commands/ConfigGetCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Anonymizer.Cli.Commands;
namespace Anonymizer.Commands;

internal sealed class ConfigGetCommand : Command
{
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/Commands/ConfigSetCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Anonymizer.Cli.Commands;
namespace Anonymizer.Commands;

internal sealed class ConfigSetCommand : Command
{
Expand Down
18 changes: 7 additions & 11 deletions src/Cli/Commands/DownloadCommand.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System.CommandLine;
using System.IO.Compression;

using Anonymizer.Cli.Downloaders;
using Anonymizer.Downloaders;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Anonymizer.Cli.Commands;
namespace Anonymizer.Commands;

internal sealed class DownloadCommand : Command
internal sealed partial class DownloadCommand : Command
{
private const string HelpDesc = """
Download PII NER and face-recognition models.
Expand All @@ -20,16 +20,13 @@ public DownloadCommand(IHostBuilder builder) : base("download", HelpDesc) =>
var app = builder.Build();

var modelDownloader = app.Services.GetRequiredService<ModelDownloader>();
var piiModelTask = DownloadAndUncompress(modelDownloader, Models.PII.Model.RemoteUri, Application.Models.PII.Dir, cancellationToken);
var faceModelTask = DownloadAndUncompress(modelDownloader, Models.Face.Model.RemoteUri, Application.Models.Face.Dir, cancellationToken);
await Task.WhenAll(piiModelTask, faceModelTask);
await DownloadAndUncompress(modelDownloader, Models.Face.Model.RemoteUri, Application.Models.Face.Dir, cancellationToken);
await DownloadAndUncompress(modelDownloader, Models.PII.Model.RemoteUri, Application.Models.PII.Dir, cancellationToken);
});

private static async Task DownloadAndUncompress(ModelDownloader modelDownloader, Uri remoteUri, DirectoryInfo outputDir, CancellationToken cancellationToken)
{
DirectoryInfo? modelsRoot = outputDir.Parent;
if (modelsRoot is null)
throw new InvalidOperationException("Unable to resolve models root directory.");
outputDir.Create();

string tempDirPath = Path.Combine(Path.GetTempPath(), "anonymizer-models");
Directory.CreateDirectory(tempDirPath);
Expand All @@ -42,7 +39,7 @@ private static async Task DownloadAndUncompress(ModelDownloader modelDownloader,
try
{
await modelDownloader.DownloadAsync(remoteUri, archiveFile, cancellationToken);
ZipFile.ExtractToDirectory(archiveFile.FullName, modelsRoot.FullName, overwriteFiles: true);
ZipFile.ExtractToDirectory(archiveFile.FullName, outputDir.FullName, overwriteFiles: true);
}
finally
{
Expand Down Expand Up @@ -74,4 +71,3 @@ private static void EnsureExpectedFiles(Uri remoteUri, DirectoryInfo outputDir)
}
}
}

2 changes: 1 addition & 1 deletion src/Cli/Commands/InputArgument.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.CommandLine;

namespace Anonymizer.Cli.Commands;
namespace Anonymizer.Commands;

internal sealed class InputArgument : Argument<FileSystemInfo[]>
{
Expand Down
Loading
Loading