From b3e93810537a1a98b60ab1e4de207137c9601ba4 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Fri, 7 Aug 2026 21:34:49 -0500 Subject: [PATCH] Add D library, CLI, Qt GUI scaffolding, docs, and multi-OS CI/releases. Moves the supported surface to DUB while keeping legacy C sources for reference. Co-authored-by: Cursor --- .github/workflows/ci.yml | 64 ++++++ .github/workflows/release.yml | 104 ++++++++++ .gitignore | 14 ++ CHANGELOG.adoc | 14 ++ LICENSE | 23 ++ README.md | 242 ++++------------------ docs/antora.yml | 6 + docs/modules/ROOT/nav.adoc | 4 + docs/modules/ROOT/pages/index.adoc | 19 ++ docs/modules/ROOT/pages/installation.adoc | 38 ++++ docs/modules/ROOT/pages/library.adoc | 16 ++ docs/modules/ROOT/pages/usage.adoc | 19 ++ dub.json | 45 ++++ source/app_cli.d | 22 ++ source/app_gui.d | 94 +++++++++ 15 files changed, 518 insertions(+), 206 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 CHANGELOG.adoc create mode 100644 LICENSE create mode 100644 docs/antora.yml create mode 100644 docs/modules/ROOT/nav.adoc create mode 100644 docs/modules/ROOT/pages/index.adoc create mode 100644 docs/modules/ROOT/pages/installation.adoc create mode 100644 docs/modules/ROOT/pages/library.adoc create mode 100644 docs/modules/ROOT/pages/usage.adoc create mode 100644 dub.json create mode 100644 source/app_cli.d create mode 100644 source/app_gui.d diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9119ebe --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,64 @@ +name: CI + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + build: + name: ${{ matrix.config }} ${{ matrix.os }} ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + arch: x86_64 + config: cli + - os: ubuntu-24.04-arm + arch: arm64 + config: cli + - os: windows-latest + arch: x86_64 + config: cli + - os: macos-latest + arch: arm64 + config: cli + - os: macos-13 + arch: x86_64 + config: cli + - os: ubuntu-latest + arch: x86_64 + config: library + - os: windows-latest + arch: x86_64 + config: library + - os: macos-latest + arch: arm64 + config: library + steps: + - uses: actions/checkout@v4 + - name: Install D + uses: dlang-community/setup-dlang@v1 + with: + compiler: ldc-latest + - name: Build + run: dub build --config=${{ matrix.config }} --build=release + + gui-linux: + name: gui ubuntu-latest x86_64 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Qt + run: | + sudo apt-get update + sudo apt-get install -y qt6-base-dev + - name: Install D + uses: dlang-community/setup-dlang@v1 + with: + compiler: ldc-latest + - name: Build GUI + run: dub build --config=gui --build=release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..55a73a4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,104 @@ +name: Release + +on: + push: + tags: ['v*'] + +permissions: + contents: write + +jobs: + build: + name: Build ${{ matrix.asset }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + asset: ver-linux-x86_64 + lib: libver-linux-x86_64.a + lib_glob: '*.a' + - os: ubuntu-24.04-arm + asset: ver-linux-arm64 + lib: libver-linux-arm64.a + lib_glob: '*.a' + - os: windows-latest + asset: ver-windows-x86_64.exe + lib: ver-windows-x86_64.lib + lib_glob: '*.lib' + - os: macos-latest + asset: ver-macos-arm64 + lib: libver-macos-arm64.a + lib_glob: '*.a' + - os: macos-13 + asset: ver-macos-x86_64 + lib: libver-macos-x86_64.a + lib_glob: '*.a' + steps: + - uses: actions/checkout@v4 + - name: Install D + uses: dlang-community/setup-dlang@v1 + with: + compiler: ldc-latest + - name: Build CLI + run: dub build --config=cli --build=release + - name: Build library + run: dub build --config=library --build=release + - name: Stage artifacts + shell: bash + run: | + set -euo pipefail + shopt -s nullglob + if [[ "${{ runner.os }}" == "Windows" ]]; then + mv ver.exe "${{ matrix.asset }}" + else + mv ver "${{ matrix.asset }}" + fi + libs=( ${{ matrix.lib_glob }} ) + cp "${libs[0]}" "${{ matrix.lib }}" + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.asset }} + path: | + ${{ matrix.asset }} + ${{ matrix.lib }} + + gui-linux: + name: Build ver-gui-linux-x86_64 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Qt + run: | + sudo apt-get update + sudo apt-get install -y qt6-base-dev + - name: Install D + uses: dlang-community/setup-dlang@v1 + with: + compiler: ldc-latest + - name: Build GUI + run: dub build --config=gui --build=release + - name: Stage + run: mv ver-gui ver-gui-linux-x86_64 + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: ver-gui-linux-x86_64 + path: ver-gui-linux-x86_64 + + release: + needs: [build, gui-linux] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + - name: Publish GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: dist/* + generate_release_notes: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20e5484 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.dub/ +*.exe +*.o +*.obj +*.lib +*.a +*.so +*.dylib +ver +ver-gui +bin/ +build/ +*.lst +dub.selections.json diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc new file mode 100644 index 0000000..fc5bb90 --- /dev/null +++ b/CHANGELOG.adoc @@ -0,0 +1,14 @@ += Changelog + +All notable changes to this project are documented in this file. + +== Unreleased + +* Relocate project to `dev-centr/ver` +* Add D library (`ver`), CLI (`ver`), and Qt GUI (`ver-gui`) builds via DUB +* Add multi-OS CI and tagged release artifacts (CLI + static library; Linux GUI) +* Keep legacy C sources under `src/` for reference (Makefile still targets them) + +== 0.1.0 + +* Initial C prototype (git/svn/local handlers) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 43bd8fa..293b609 100644 --- a/README.md +++ b/README.md @@ -1,243 +1,73 @@
- Contributors - Forks - Stargazers - Issues - License + Contributors + Forks + Stargazers + Issues + License

Ver

-

Universal Version Control Interface — pluggable system for Git, SVN, and other VCS providers with intuitive syntax.

+

Universal Version Control Interface — library, CLI, and Qt GUI with one command model across Git, SVN, and Mercurial.

- Report Bug + Explore the docs · - Request Feature + Report Bug + · + Request Feature

-
- Table of Contents -
    -
  1. - About The Project - -
  2. -
  3. Installation
  4. -
  5. Usage
  6. -
  7. Contributing
  8. -
  9. License
  10. -
  11. Contact
  12. -
-
- ## About The Project -Ver is a pluggable version control interface that provides a unified, intuitive command-line experience across different version control systems. It aims to eliminate the cognitive overhead of learning multiple VCS commands by providing a consistent mental model and syntax. - -### Features +Ver maps a small, consistent vocabulary (`status`, `save`, `sync`, …) onto the nearest VCS root. Use it as a **CLI**, embed the **D library**, or open the **Qt GUI**. -- **Provider Agnostic**: Works with Git, SVN, Mercurial, and custom providers -- **Intuitive Syntax**: Commands like `ver save`, `ver history`, `ver sync` -- **Handler-Based Architecture**: Pluggable system for adding new VCS providers -- **Auto-Detection**: Automatically detects the VCS provider for your project -- **Safety Rails**: Prevents common mistakes with built-in safeguards -- **Cross-Shell Support**: Works in CMD, PowerShell, and Unix shells - -

(back to top)

+Legacy C sources under `src/` remain for reference; the supported build is DUB (`source/`). ### Built With -* **CLI / core** — C (Make-based build), handler plugins under `src/handlers/` -* **Providers** — Git (gitu-handler preferred), SVN, Mercurial, local snapshots -* **Shells** — CMD, PowerShell, bash/zsh - -

(back to top)

+* **D** — library + CLI + GUI +* **DUB** — package / build +* **Qt 6 + dqt** — optional GUI (`dlang-supplemental/dqt`) ## Installation ```bash -# Clone the repository -git clone https://github.com/AMDphreak/ver.git -cd ver - -# Build the project -make - -# Install system-wide -make install -``` - -

(back to top)

- -## Usage - -### Basic commands - -```bash -# Initialize a new project (defaults to gitu provider) -ver init - -# Save changes -ver save "Fixed login bug" - -# View history -ver history - -# Sync with remote -ver sync - -# Check status -ver status -``` - -### Architecture - -Ver uses a handler-based architecture where: - -1. **CLI Dispatcher** (`ver`) - Parses commands and detects providers -2. **Abstraction Layer** - Maps intuitive commands to provider-specific actions -3. **Provider Handlers** - Execute the actual VCS commands - -#### Included Handlers - -- **gitu-handler** - Uses the improved gitu interface (Git Unfuckified) -- **git-handler** - Standard Git compatibility -- **local-handler** - Local file snapshots without remote - -### Command Mapping - -| Ver Command | Git Equivalent | SVN Equivalent | Description | -|-------------|----------------|----------------|-------------| -| `ver init` | `git init` | `svn init` | Initialize repository | -| `ver save` | `git commit` | `svn commit` | Save changes | -| `ver stage` | `git add` | `svn add` | Stage files | -| `ver history` | `git log` | `svn log` | View history | -| `ver sync` | `git pull && git push` | `svn update && svn commit` | Synchronize | -| `ver branch` | `git branch` | `svn copy` | Manage branches | -| `ver merge` | `git merge` | `svn merge` | Merge changes | - -### Provider Detection - -Ver automatically detects the version control provider by looking for: - -- `.git/` directory → gitu-handler (preferred) or git-handler -- `.svn/` directory → svn-handler -- `.hg/` directory → hg-handler -- `.ver/` directory → local-handler - -### Development - -#### Project Structure - -``` -ver/ -├── src/ -│ ├── core/ # CLI dispatcher logic -│ ├── handlers/ # Provider handlers -│ └── tui/ # Terminal UI components -├── plugins/ # External handler plugins -├── tests/ # Test suites -└── docs/ # Documentation -``` - -#### Adding New Handlers - -1. Create a handler in `src/handlers/` -2. Implement the required interface functions -3. Register the handler in the core dispatcher -4. Add tests - -See `docs/handler-development.md` for details. - -### Shell Integration - -#### PowerShell - -Add to your `$PROFILE`: - -```powershell -function ver { & ver.exe $args } -``` - -#### CMD - -Create a doskey macro: - -```batch -doskey ver=ver.exe $* -``` - -#### Unix Shells - -Add to your `.bashrc` or `.zshrc`: - -```bash -alias ver='ver.exe' +dub build --config=cli --build=release +dub build --config=library --build=release +# optional: +dub build --config=gui --build=release ``` -### Configuration - -Ver stores configuration in: - -- **Windows**: `%APPDATA%/ver/config.json` -- **Unix**: `~/.config/ver/config.json` - -Example configuration: +As a dependency (DUB registry after first publish, or git): ```json -{ - "default_provider": "gitu", - "handlers": { - "gitu": { - "path": "./plugins/gitu-handler", - "priority": 1 - }, - "git": { - "path": "./plugins/git-handler", - "priority": 2 - } - }, - "ui": { - "tui_enabled": true, - "ai_mode": false +"dependencies": { + "ver": { + "repository": "git+https://github.com/dev-centr/ver.git", + "version": "~main" } } ``` -

(back to top)

- -## Contributing - -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Add tests -5. Submit a pull request - -### Top contributors +## Usage - - contributors - +```bash +ver status +ver save "message" +ver sync +ver-gui +``` -For per-person profile links, prefer [all-contributors](https://allcontributors.org/). +## Changelog -

(back to top)

+See [CHANGELOG.adoc](./CHANGELOG.adoc). ## License -MIT License — see [LICENSE](LICENSE) for details. - -

(back to top)

+Boost Software License 1.0 — see [LICENSE](./LICENSE). ## Contact -Ryan Johnson — [@amdphreak](https://twitter.com/amdphreak) - -Project Link: [https://github.com/AMDphreak/ver](https://github.com/AMDphreak/ver) - -Site: [https://ryanjohnson.dev](https://ryanjohnson.dev) +Dev-Centr — support@devcentr.org -

(back to top)

+Project Link: https://github.com/dev-centr/ver diff --git a/docs/antora.yml b/docs/antora.yml new file mode 100644 index 0000000..3033f34 --- /dev/null +++ b/docs/antora.yml @@ -0,0 +1,6 @@ +name: ver +title: Ver +version: master +start_page: ROOT:index.adoc +nav: + - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc new file mode 100644 index 0000000..bf4b67f --- /dev/null +++ b/docs/modules/ROOT/nav.adoc @@ -0,0 +1,4 @@ +* xref:index.adoc[Overview] +* xref:installation.adoc[Installation] +* xref:usage.adoc[Usage] +* xref:library.adoc[Library API] diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc new file mode 100644 index 0000000..8d6b4fd --- /dev/null +++ b/docs/modules/ROOT/pages/index.adoc @@ -0,0 +1,19 @@ += Ver +:description: Universal version-control interface — one command model across Git, SVN, and Mercurial. + +Ver is a developer tool that maps a small, consistent command vocabulary (`status`, `save`, `sync`, …) onto the nearest VCS root. + +== Surfaces + +* *Library* (`ver`) — embed detection and dispatch in other D tools +* *CLI* (`ver`) — day-to-day shell use +* *GUI* (`ver-gui`) — Qt front-end over the same library + +Repository:: +https://github.com/dev-centr/ver + +Docs hub:: +https://docs.devcentr.org/ver/ + +Package index:: +https://code.dlang.org/packages/ver (DUB; register after the first tagged release) diff --git a/docs/modules/ROOT/pages/installation.adoc b/docs/modules/ROOT/pages/installation.adoc new file mode 100644 index 0000000..c507925 --- /dev/null +++ b/docs/modules/ROOT/pages/installation.adoc @@ -0,0 +1,38 @@ += Installation + +== From source (DUB) + +[source,bash] +---- +git clone https://github.com/dev-centr/ver.git +cd ver +dub build --config=cli --build=release +dub build --config=library --build=release +# Optional Qt GUI (needs Qt 6 + dqt): +dub build --config=gui --build=release +---- + +== As a DUB dependency + +[source,json] +---- +"dependencies": { + "ver": "~>0.2.0" +} +---- + +Until the package is on https://code.dlang.org[code.dlang.org], depend on git: + +[source,json] +---- +"dependencies": { + "ver": { + "repository": "git+https://github.com/dev-centr/ver.git", + "version": "~main" + } +} +---- + +== Releases + +GitHub Releases attach CLI binaries and static libraries for Linux/Windows/macOS (x86_64 and arm64 where runners exist), plus a Linux `ver-gui` build. diff --git a/docs/modules/ROOT/pages/library.adoc b/docs/modules/ROOT/pages/library.adoc new file mode 100644 index 0000000..ac56c94 --- /dev/null +++ b/docs/modules/ROOT/pages/library.adoc @@ -0,0 +1,16 @@ += Library API + +[source,d] +---- +import ver; + +auto kind = detectVcs("."); +auto result = dispatch("status", null, "."); +---- + +Key entry points: + +* `detectVcs` / `findVcsRoot` — discovery +* `dispatch` — command mapping +* `CommandResult` — exit code + captured output +* `verVersion` — library/CLI version string diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc new file mode 100644 index 0000000..9ee0652 --- /dev/null +++ b/docs/modules/ROOT/pages/usage.adoc @@ -0,0 +1,19 @@ += Usage + +[source,bash] +---- +ver status +ver save "explain the change" +ver sync +ver history +ver help +---- + +`ver` walks upward from the current directory to find `.git`, `.svn`, or `.hg`, then maps the command onto that tool. + +GUI: + +[source,bash] +---- +ver-gui +---- diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..11e1382 --- /dev/null +++ b/dub.json @@ -0,0 +1,45 @@ +{ + "name": "ver", + "description": "Universal version-control interface — library, CLI, and Qt GUI with a consistent command model.", + "authors": ["Dev-Centr"], + "license": "BSL-1.0", + "copyright": "Copyright © 2024–2026, Dev-Centr", + "homepage": "https://github.com/dev-centr/ver", + "documentationURL": "https://docs.devcentr.org/ver/", + "sourcePaths": ["source"], + "importPaths": ["source"], + "configurations": [ + { + "name": "library", + "targetType": "library", + "excludedSourceFiles": [ + "source/app_cli.d", + "source/app_gui.d" + ] + }, + { + "name": "cli", + "targetType": "executable", + "targetName": "ver", + "mainSourceFile": "source/app_cli.d", + "excludedSourceFiles": [ + "source/app_gui.d" + ] + }, + { + "name": "gui", + "targetType": "executable", + "targetName": "ver-gui", + "mainSourceFile": "source/app_gui.d", + "excludedSourceFiles": [ + "source/app_cli.d" + ], + "dependencies": { + "dqt:widgets": { + "repository": "git+https://github.com/dlang-supplemental/dqt.git", + "version": "~master" + } + } + } + ] +} diff --git a/source/app_cli.d b/source/app_cli.d new file mode 100644 index 0000000..119b404 --- /dev/null +++ b/source/app_cli.d @@ -0,0 +1,22 @@ +module app_cli; + +import std.stdio : stderr, write, writeln; +import ver; + +int main(string[] args) +{ + if (args.length < 2) + { + write(helpText()); + return 0; + } + + auto result = dispatch(args[1], args[2 .. $]); + if (result.stdout.length) + write(result.stdout); + if (result.stderr.length) + stderr.write(result.stderr); + if (result.exitCode != 0 && result.stderr.length == 0 && result.stdout.length == 0) + stderr.writeln(result.handlerName, ": command failed with code ", result.exitCode); + return result.exitCode; +} diff --git a/source/app_gui.d b/source/app_gui.d new file mode 100644 index 0000000..596274b --- /dev/null +++ b/source/app_gui.d @@ -0,0 +1,94 @@ +/** ver-gui — Qt front-end for the Ver library. */ +module app_gui; + +import core.runtime; +import core.stdcpp.new_; + +import qt.config; +import qt.core.object; +import qt.core.string; +import qt.helpers; +import qt.widgets.application; +import qt.widgets.boxlayout; +import qt.widgets.label; +import qt.widgets.lineedit; +import qt.widgets.mainwindow; +import qt.widgets.plaintextedit; +import qt.widgets.pushbutton; +import qt.widgets.widget; + +import ver; + +class VerWindow : QMainWindow +{ + mixin(Q_OBJECT_D); + + this(QWidget parent = null) + { + super(parent); + setWindowTitle("Ver"); + resize(720, 480); + + auto central = cpp_new!QWidget(this); + auto layout = cpp_new!QVBoxLayout(central); + + auto title = cpp_new!QLabel(central); + title.setText("Ver — universal VCS interface"); + layout.addWidget(title); + + auto prompt = cpp_new!QLabel(central); + prompt.setText("Command (e.g. status, history, save hello)"); + layout.addWidget(prompt); + + input = cpp_new!QLineEdit(central); + layout.addWidget(input); + + auto runBtn = cpp_new!QPushButton(central); + runBtn.setText("Run"); + layout.addWidget(runBtn); + + output = cpp_new!QPlainTextEdit(central); + output.setReadOnly(true); + layout.addWidget(output); + + setCentralWidget(central); + + connect(runBtn.signal!"clicked", this.slot!"onRun"); + connect(input.signal!"returnPressed", this.slot!"onRun"); + } + +private /+ slots +/: + @QSlot final void onRun() + { + import std.array : split; + import std.conv : to; + import std.string : strip; + + auto line = input.text().to!string.strip; + if (line.length == 0) + return; + auto parts = line.split(); + auto result = dispatch(parts[0], parts.length > 1 ? parts[1 .. $] : null); + auto text = result.stdout; + if (result.stderr.length) + text ~= (text.length ? "\n" : "") ~ result.stderr; + if (text.length == 0) + text = "(exit " ~ result.exitCode.to!string ~ " via " ~ result.handlerName ~ ")"; + output.setPlainText(QString(text)); + } + +private: + QLineEdit input; + QPlainTextEdit output; +} + +int main() +{ + int argc = Runtime.cArgs.argc; + char** argv = Runtime.cArgs.argv; + scope app = new QApplication(argc, argv); + + auto window = cpp_new!VerWindow(); + window.show(); + return app.exec(); +}