diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..72339b5 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,80 @@ +# CI/CD Workflows + +This directory contains GitHub Actions workflows for the go-syspkg project. + +## Workflows + +### 1. Test and Coverage (`test-and-coverage.yml`) +Runs comprehensive tests with coverage reporting: +- **Go Versions**: 1.23, 1.24 (project requires Go 1.23+) +- **Platform**: Ubuntu Latest +- **Coverage**: Uploads test coverage to Codecov +- **Race Detection**: Runs tests with race detector enabled + +### 2. Lint and Format (`lint-and-format.yml`) +Ensures code quality and formatting standards: +- **gofmt**: Checks code formatting +- **go vet**: Reports suspicious constructs +- **golangci-lint**: Comprehensive linting with multiple linters +- **go mod tidy**: Ensures go.mod and go.sum are up to date + +### 3. Build (`build.yml`) +Verifies code builds across Go versions: +- **Go Versions**: 1.23, 1.24 +- **Build Targets**: All packages and CLI binary +- **Platform**: Ubuntu Latest + +### 4. Release Binaries (`release-binaries.yml`) +Creates cross-platform release binaries: +- **Platforms**: Linux, Windows, Darwin +- **Architectures**: amd64, arm64, 386 (where supported) +- **Go Version**: 1.24 +- **Trigger**: On GitHub releases + +## Local Development + +### Running Checks Locally +```bash +# Format code +make format + +# Check formatting and run linters +make check + +# Run specific checks +gofmt -l . # List files that need formatting +go vet ./... # Run go vet +golangci-lint run # Run all linters +``` + +### Pre-commit Hooks +Install pre-commit to run checks automatically before commits: +```bash +pre-commit install +``` + +Pre-commit hooks include: +- File hygiene (trailing whitespace, EOF, merge conflicts) +- Go tools (gofmt, goimports, go vet, go mod tidy, golangci-lint) +- Build verification (go build, go mod verify) +- Security-focused using local system tools only + +## Configuration Files + +- `.golangci.yml`: Configures golangci-lint with enabled/disabled linters +- `.pre-commit-config.yaml`: Defines pre-commit hooks +- `Makefile`: Contains format and check targets + +## Adding New Checks + +To add new linting rules: +1. Update `.golangci.yml` to enable/disable linters +2. Update the `lint-and-format.yml` workflow if needed +3. Test locally with `make check` + +## Project Standards + +- **License**: Apache License 2.0 (patent protection and enterprise clarity) +- **Go Version**: 1.23+ required, CI tests with 1.23 and 1.24 +- **Code Quality**: Enforced via pre-commit hooks and CI workflows +- **Security**: Local system tools used in pre-commit for maximum security diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..c34f8d3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,40 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Build + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + name: Build + runs-on: ubuntu-latest + strategy: + matrix: + go-version: ['1.23', '1.24'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + cache: true + + - name: Install dependencies + run: go mod download + + - name: Build + run: go build -v ./... + + - name: Build CLI binary + run: go build -v ./cmd/syspkg diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 3e9a76d..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,28 +0,0 @@ -# This workflow will build a golang project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go - -name: Go - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.19 - - - name: Build - run: go build -v ./... - - - name: Test - run: go test -v ./... diff --git a/.github/workflows/lint-and-format.yml b/.github/workflows/lint-and-format.yml new file mode 100644 index 0000000..bea7473 --- /dev/null +++ b/.github/workflows/lint-and-format.yml @@ -0,0 +1,58 @@ +name: Lint and Format + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: read + +jobs: + lint: + name: Lint and Format Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.23' + cache: true + + - name: Install dependencies + run: | + go mod download + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + + - name: Run gofmt + run: | + # Check if gofmt reports any formatting issues + if [ -n "$(gofmt -l .)" ]; then + echo "The following files need formatting:" + gofmt -l . + echo "" + echo "Please run 'gofmt -w .' to format your code" + exit 1 + fi + + - name: Run go vet + run: go vet ./... + + - name: Run golangci-lint + run: golangci-lint run --timeout=5m + + - name: Run go mod tidy check + run: | + go mod tidy + if [ -n "$(git status --porcelain)" ]; then + echo "go mod tidy produced changes:" + git diff + echo "" + echo "Please run 'go mod tidy' and commit the changes" + exit 1 + fi diff --git a/.github/workflows/go-release-binaries.yml b/.github/workflows/release-binaries.yml similarity index 69% rename from .github/workflows/go-release-binaries.yml rename to .github/workflows/release-binaries.yml index ce12842..ce354ef 100644 --- a/.github/workflows/go-release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -1,9 +1,13 @@ # .github/workflows/go-release-binaries.yml -name: Go Release Binaries +name: Release Binaries + on: release: types: [created] +permissions: + contents: write + jobs: releases-matrix: name: Release Go Binary @@ -19,22 +23,24 @@ jobs: - goarch: arm64 goos: windows steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + go-version: '1.24' + cache: true + + - name: Install dependencies + run: go mod download + - uses: wangyoucao577/go-release-action@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} goos: ${{ matrix.goos }} goarch: ${{ matrix.goarch }} - goversion: https://dl.google.com/go/go1.20.3.linux-amd64.tar.gz + go_version: '1.24' project_path: ./cmd/syspkg binary_name: syspkg extra_files: LICENSE README.md - diff --git a/.github/workflows/test-and-coverage.yml b/.github/workflows/test-and-coverage.yml new file mode 100644 index 0000000..f008240 --- /dev/null +++ b/.github/workflows/test-and-coverage.yml @@ -0,0 +1,44 @@ +name: Test and Coverage + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: read + +jobs: + test: + name: Test and Coverage + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + go-version: ['1.23', '1.24'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + cache: true + + - name: Install dependencies + run: go mod download + + - name: Run tests + run: | + go test -v -race -coverprofile=coverage.txt -covermode=atomic ./... + + - name: Upload coverage to Codecov + if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23' + uses: codecov/codecov-action@v4 + with: + file: ./coverage.txt + flags: unittests + name: codecov-umbrella diff --git a/.gitignore b/.gitignore index 98c9d3d..fda9ea0 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,13 @@ go.work bin/ tmp/ -**/*.log \ No newline at end of file +**/*.log.dccache + +# Development cache and temporary files +.dccache +*.log + +# Temporary development notes (not part of official docs) +*_improvements.md +*_notes.md +*_todo.md diff --git a/.go-version b/.go-version deleted file mode 100644 index 5f088a8..0000000 --- a/.go-version +++ /dev/null @@ -1,2 +0,0 @@ -golang 1.20.6 - diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..81a45bf --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,102 @@ +# golangci-lint configuration +# https://golangci-lint.run/usage/configuration/ + +run: + timeout: 5m + tests: true + exclude-dirs: + - vendor + - testdata + - testing + +linters: + enable: + # Default linters + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - typecheck + - unused + # Additional linters + - gofmt + - goimports + - misspell + - unconvert + - gocyclo + - goprintffuncname + - gosec + - nakedret + - noctx + - nolintlint + - predeclared + - thelper + - tparallel + - unparam + + disable: + - depguard + - dogsled + - dupl + - funlen + - gochecknoinits + - goconst + - gocritic + - gocognit + - lll + - nestif + - testpackage + - wrapcheck + - exhaustive + - exhaustruct + - nlreturn + +linters-settings: + gofmt: + simplify: true + goimports: + local-prefixes: github.com/bluet/syspkg + govet: + enable: + - shadow + misspell: + locale: US + gocyclo: + min-complexity: 20 + +issues: + exclude-rules: + # Exclude some linters from running on tests files + - path: _test\.go + linters: + - gosec + - gocyclo + + # Exclude shadow warning for common patterns + - linters: + - govet + text: "shadow: declaration of \"err\"" + + # Exclude misspelling in specific cases + - linters: + - misspell + text: "cancelled" + + # Exclude unnecessary conversion in utils (string([]byte) is explicit) + - path: utils\.go + linters: + - unconvert + text: "unnecessary conversion" + + # Exclude high cyclomatic complexity for main function + - path: cmd/syspkg/main\.go + linters: + - gocyclo + text: "cyclomatic complexity.*of func `main`" + + # Maximum issues count per one linter + max-issues-per-linter: 50 + + # Maximum count of issues with the same text + max-same-issues: 10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..776b679 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,96 @@ +# See https://pre-commit.com for more information +repos: + # Official pre-commit hooks (maintained by pre-commit organization) + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-merge-conflict + - id: check-case-conflict + - id: check-json + - id: check-toml + - id: mixed-line-ending + + # Google's official pre-commit tool hooks (optional - uncomment if needed) + # - repo: https://github.com/google/pre-commit-tool-hooks + # rev: v1.2.5 + # hooks: + # - id: check-copyright + # args: ['--copyright', 'Copyright YYYY'] + + # Go-specific hooks using local system tools (most secure approach) + - repo: local + hooks: + - id: go-fmt + name: go-fmt + entry: gofmt + args: [-w, -s] + language: system + files: \.go$ + description: Run gofmt to format Go code + + - id: go-imports + name: go-imports + entry: goimports + args: [-w, -local, github.com/bluet/syspkg] + language: system + files: \.go$ + description: Run goimports to organize imports per Go Code Review guidelines + + - id: go-vet + name: go-vet + entry: go + args: [vet, ./...] + language: system + files: \.go$ + pass_filenames: false + description: Run go vet to check for suspicious constructs + + - id: go-mod-tidy + name: go-mod-tidy + entry: go + args: [mod, tidy] + language: system + files: ^go\.(mod|sum)$ + pass_filenames: false + description: Run go mod tidy to ensure dependencies are clean + + - id: golangci-lint + name: golangci-lint + entry: golangci-lint + args: [run, --fix] + language: system + files: \.go$ + pass_filenames: false + description: Run golangci-lint with auto-fix + + # Uncomment for stricter pre-commit (may be slow): + # - id: go-test + # name: go-test + # entry: go + # args: [test, -v, ./...] + # language: system + # files: \.go$ + # pass_filenames: false + # description: Run go test to ensure code compiles and passes tests + + - id: go-build + name: go-build + entry: go + args: [build, ./...] + language: system + files: \.go$ + pass_filenames: false + description: Check that packages can be built + + - id: go-mod-verify + name: go-mod-verify + entry: go + args: [mod, verify] + language: system + files: ^go\.(mod|sum)$ + pass_filenames: false + description: Verify dependencies have expected content diff --git a/.tool-versions b/.tool-versions index d7c5a5a..6d51b8f 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1 @@ -golang 1.21.5 - +golang 1.24.3 diff --git a/.vscode/settings.json b/.vscode/settings.json index 85c81fb..fc8a490 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,4 +28,4 @@ "zutty", "zvbi" ] -} \ No newline at end of file +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..825a2ec --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,150 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Development Commands + +### Build +```bash +make build # Build for current platform +make build-all-arch # Build for all supported platforms +make all # Run tests and then build +``` + +Binary output: `bin/syspkg` + +### Test +```bash +make test # Run all tests with verbose output +go test ./manager/apt -v # Run tests for specific package +``` + +### Lint and Format +```bash +make lint # Run go mod tidy, golangci-lint, and gofmt +make format # Format code with gofmt and goimports +make check # Run all code quality checks (formatting, linting, vet) +make install-tools # Install required tools (golangci-lint) +``` + +### Pre-commit Hooks +```bash +pre-commit install # Install pre-commit hooks +pre-commit run --all-files # Run all hooks on all files +``` + +**Pre-commit hooks include:** +- File hygiene (trailing whitespace, EOF, merge conflicts) +- Go tools (gofmt, goimports, go vet, go mod tidy, golangci-lint) +- Build verification (go build, go mod verify) +- Security-focused using local system tools only + +### CI/CD Workflows +Located in `.github/workflows/`: +- **test-and-coverage.yml**: Go 1.23/1.24 testing with coverage +- **lint-and-format.yml**: Code quality and formatting checks +- **build.yml**: Multi-version build verification +- **release-binaries.yml**: Cross-platform binary releases + +## Architecture Overview + +### Core Interfaces +- `PackageManager` (interface.go): Defines methods all package managers must implement +- `SysPkg` (interface.go): High-level interface for managing multiple package managers + +### Package Structure +- `/cmd/syspkg/`: CLI application using urfave/cli/v2 framework +- `/manager/`: Package manager implementations + - Each manager (apt, snap, flatpak) has its own directory + - Common types in `options.go` and `packageinfo.go` +- `/osinfo/`: OS detection utilities for determining available package managers + +### Key Design Patterns +- Interface-based abstraction allows easy addition of new package managers +- Factory pattern in `syspkg.go` for creating manager instances +- Options pattern for configurable behavior (manager.Options) + +### Adding New Package Managers +1. Create new directory under `/manager/` +2. Implement the `PackageManager` interface +3. Add to `initializePackageManagers()` in `syspkg.go` +4. Add tests following existing patterns (parse functions, availability checks) + +### Testing Patterns +- Unit tests use table-driven tests with mock data +- Integration tests check actual package manager availability +- Parse functions are heavily tested with real command output examples +- Tests use `*_test` package naming for better encapsulation + +### CLI Command Structure +Main commands: `install`, `delete`, `refresh`, `upgrade`, `find`, `show` +Package manager flags: `--apt`, `--flatpak`, `--snap` +Options: `--debug`, `--assume-yes`, `--dry-run`, `--interactive`, `--verbose` + +## Important Notes + +- **License**: Apache License 2.0 (provides patent protection and enterprise-grade legal clarity) +- **Go Version**: Requires Go 1.23+ (CI tests with 1.23, 1.24) +- **Code Quality**: Always run `make check` before committing to ensure quality +- **Pre-commit**: Hooks automatically enforce formatting, linting, and security checks +- **Package Managers**: When implementing new ones, focus on parsing command outputs correctly +- **CLI Detection**: Automatically detects available package managers if no flag is specified +- **Privileges**: Root privileges are often required for package operations + +## Philosophy + +**Tool-Focused Approach**: SysPkg focuses on supporting package manager tools based on their functionality rather than the operating system they're running on. If apt+dpkg work correctly in a container, on macOS via Homebrew, or in any other environment, SysPkg will support them. This makes the project more flexible and useful across different development environments. + +## Project Improvement Roadmap + +*Note: To-do list consolidated 2025-05-30 - removed duplicates, feature creep items, and over-engineering. Focused on core security, testing, and platform support.* + +### ๐Ÿ”ด High Priority (Security & Critical Bugs) - 4 items +1. **Fix command injection vulnerability** - validate/sanitize package names before exec.Command +2. **Implement input validation helper function** for package names and arguments +3. **Fix resource leaks** in error handling paths +4. **Add security scanning with Snyk** to CI/CD pipeline +5. **Review and merge PR #12** - fix GetPackageManager("") panic bug โœ… + +### ๐ŸŸก Medium Priority (Code Quality & Testing) - 7 items +**Testing:** +- Create integration tests with mocked command execution +- Add unit tests for snap package manager +- Add unit tests for flatpak package manager + +**Code Improvements:** +- Implement context support for cancellation and timeouts +- Create custom error types for better error handling +- Extract common parsing logic to shared utilities (DRY principle) +- Replace magic strings/numbers with named constants + +**Removed from roadmap (2025-05-30):** +- ~~Structured logging~~ (over-engineering for project scope) +- ~~Progress indicators~~ (feature creep for CLI/library) +- ~~Architecture diagrams~~ (low ROI for library project) +- ~~TODO comment fixes~~ (covered by security improvements) + +### ๐ŸŸข Low Priority (Platform Support) - 3 items +**New Package Managers:** +- Add proper macOS support with brew package manager implementation +- Add Windows support with chocolatey/scoop/winget package managers +- Implement dnf/yum package manager support (Red Hat/Fedora) + +**Removed from roadmap (2025-05-30):** +- ~~zypper, apk support~~ (lower priority than core platforms) +- ~~Parallel operations~~ (premature optimization) + +## Testing Strategy Notes + +### Docker Testing Capabilities +- **Works Well**: APT, DNF/YUM, APK, Flatpak (limited) - for capturing command outputs and testing parsers +- **Doesn't Work**: Snap (requires systemd), actual package installations +- **Best Practice**: Use Docker to capture real outputs, then use mocks for testing + +### Testing Approach +1. **Unit Tests**: Parser functions with captured fixtures +2. **Integration Tests**: Mock exec.Command for package operations +3. **Docker Tests**: Multi-OS parser validation with real command outputs +4. **CI/CD Tests**: Native runners for snap and full integration tests + +See `testing/docker/` for implementation details and strategies. diff --git a/LICENSE b/LICENSE index 4a06ca2..aab6302 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,164 @@ -MIT License - -Copyright (c) 2023 BlueT - Matthew Lien - ็ทดๅ–†ๆ˜Ž - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (which shall not include communications that are solely to announce + the name of the work and do not include the copyright notice itself). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based upon (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and derivative works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control + systems, and issue tracking systems that are managed by, or on behalf + of, the Licensor for the purpose of discussing and improving the Work, + but excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to use, reproduce, modify, distribute, and prepare + Derivative Works of, publicly display, publicly perform, sublicense, + and sell the Work and such Derivative Works in source or object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You must retain, on all copies of the Work or + Derivative Works thereof, the following copyright notice: + + Copyright 2023-2025 BlueT - Matthew Lien - ็ทดๅ–†ๆ˜Ž + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Support. While redistributing the Work or + Derivative Works thereof, You may choose to offer, and charge a fee + for, acceptance of support, warranty, indemnity, or other liability + obligations and/or rights consistent with this License. However, in + accepting such obligations, You may act only on Your own behalf and on + Your sole responsibility, not on behalf of any other Contributor, and + only if You agree to indemnify, defend, and hold each Contributor + harmless for any liability incurred by, or claims asserted against, + such Contributor by reason of your accepting any such warranty or support. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "license" line as the copyright notice for easier + identification within third-party archives. + + Copyright 2023-2025 BlueT - Matthew Lien - ็ทดๅ–†ๆ˜Ž + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile index 277df4f..d075a13 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all build build-all-arch test lint install-tools +.PHONY: all build build-all-arch test lint format fmt check install-tools # Go parameters GOCMD=go @@ -50,5 +50,38 @@ lint: golangci-lint run gofmt -s -w . +format fmt: + @echo "Running gofmt..." + @gofmt -s -w . + @echo "Running goimports..." + @go install golang.org/x/tools/cmd/goimports@latest + @goimports -w -local github.com/bluet/syspkg . + @echo "Formatting complete!" + +check: + @echo "Checking code formatting..." + @if [ -n "$$(gofmt -l .)" ]; then \ + echo "The following files need formatting:"; \ + gofmt -l .; \ + echo ""; \ + echo "Run 'make format' to fix formatting"; \ + exit 1; \ + fi + @echo "Checking go mod tidy..." + @go mod tidy + @if [ -n "$$(git status --porcelain go.mod go.sum)" ]; then \ + echo "go.mod or go.sum needs updating"; \ + echo "Run 'go mod tidy' and commit the changes"; \ + exit 1; \ + fi + @echo "Running go vet..." + @go vet ./... + @echo "Running golangci-lint..." + @golangci-lint run + @echo "All checks passed!" + install-tools: $(GOINSTALL) github.com/golangci/golangci-lint/cmd/golangci-lint@latest + +# TODO: Add Docker testing targets when Dockerfiles are implemented +# TODO: Add unit/integration test targets when build tags are added to test files diff --git a/README.md b/README.md index b2943af..92d450f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ # SysPkg -[![Go Reference](https://pkg.go.dev/badge/github.com/bluet/syspkg.svg)](https://pkg.go.dev/github.com/bluet/syspkg) +[![Test and Coverage](https://github.com/bluet/syspkg/actions/workflows/test-and-coverage.yml/badge.svg)](https://github.com/bluet/syspkg/actions/workflows/test-and-coverage.yml) +[![Build](https://github.com/bluet/syspkg/actions/workflows/build.yml/badge.svg)](https://github.com/bluet/syspkg/actions/workflows/build.yml) +[![Lint and Format](https://github.com/bluet/syspkg/actions/workflows/lint-and-format.yml/badge.svg)](https://github.com/bluet/syspkg/actions/workflows/lint-and-format.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/bluet/syspkg)](https://goreportcard.com/report/github.com/bluet/syspkg) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bluet/syspkg/blob/main/LICENSE) +[![Go Reference](https://pkg.go.dev/badge/github.com/bluet/syspkg.svg)](https://pkg.go.dev/github.com/bluet/syspkg) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/bluet/syspkg/blob/main/LICENSE) +[![Go Version](https://img.shields.io/github/go-mod/go-version/bluet/syspkg)](https://github.com/bluet/syspkg) +[![GitHub release](https://img.shields.io/github/v/release/bluet/syspkg)](https://github.com/bluet/syspkg/releases) -SysPkg is a unified CLI tool and Golang library for managing system packages across different package managers (apt, snap, flatpak, yum, dnf, and more). It simplifies the process of working with various package managers by providing a consistent interface and API through an abstraction layer. +SysPkg is a unified CLI tool and Golang library for managing system packages across different package managers. Currently, it supports APT, Snap, and Flatpak, with plans for more. It simplifies package management by providing a consistent interface and API through an abstraction layer that focuses on package manager tools rather than specific operating systems. ## Features @@ -21,7 +26,7 @@ See the [Go Reference](https://pkg.go.dev/github.com/bluet/syspkg) for the full ### Prerequisites -- Go 1.16 or later (1.20+ preferred) +- Go 1.23 or later ### Installation (as CLI tool) @@ -102,8 +107,14 @@ func main() { return } + // Get APT package manager (if available) + aptManager, err := syspkgManager.GetPackageManager("apt") + if err != nil { + fmt.Printf("APT package manager not available: %v\n", err) + return + } + // List installed packages using APT - aptManager := syspkgManager.GetPackageManager("apt") installedPackages, err := aptManager.ListInstalled(nil) if err != nil { fmt.Printf("Error listing installed packages: %v\n", err) @@ -125,16 +136,68 @@ For more examples and real use cases, see the [cmd/syspkg/](cmd/syspkg/) directo | --------------- | ------- | ------ | ------ | ------- | -------------- | --------------- | ---------------- | | APT | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | | SNAP | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | -| Flatpak | โ“ | โ“ | โœ… | โœ… | โœ… | โœ… | โœ… | -| Your favorite package manager here! | ๐Ÿš€ | ๐Ÿš€ | ๐Ÿš€ | ๐Ÿš€ | ๐Ÿš€ | ๐Ÿš€ | ๐Ÿš€ | +| Flatpak | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | +| DNF/YUM | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | +| APK (Alpine) | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | +| Zypper (openSUSE) | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | ๐Ÿšง | + +**Legend:** โœ… Implemented, ๐Ÿšง Planned, โŒ Not supported + +**Philosophy:** SysPkg focuses on supporting package manager tools wherever they work, regardless of the underlying operating system. If you have apt+dpkg working on macOS via Homebrew, or in a container, SysPkg will support it. Please open an issue (or PR โค๏ธ) if you'd like to see support for any unlisted specific package manager. +## Development + +### Documentation +- **CLAUDE.md** - Development guidelines, architecture, and project roadmap +- **testing/** - Test fixtures and Docker testing infrastructure +- **.pre-commit-config.yaml** - Secure pre-commit hooks aligned with Go best practices +- **.github/workflows/** - CI/CD pipelines for testing, linting, building, and releases + +### CI/CD Status + +| Workflow | Status | Description | +| -------- | ------ | ----------- | +| **Test and Coverage** | โœ… | Go 1.23/1.24 testing with coverage reporting | +| **Lint and Format** | โœ… | golangci-lint, gofmt, go vet quality checks | +| **Build** | โœ… | Multi-version build verification | +| **Release Binaries** | โœ… | Cross-platform binary releases | + +- โœ… **Pre-commit hooks**: Automated code quality and security checks +- โœ… **Go mod verification**: Dependency integrity validation +- ๐Ÿšง **Multi-platform testing**: macOS/Windows testing planned + +### Development Setup + +1. **Clone and setup**: + ```bash + git clone https://github.com/bluet/syspkg.git + cd syspkg + ``` + +2. **Install pre-commit hooks**: + ```bash + pre-commit install + ``` + +3. **Run development commands**: + ```bash + make test # Run tests + make check # Code quality checks + make build # Build binary + ``` + +### Contributing +See [CLAUDE.md](CLAUDE.md) for detailed development guidelines and architecture overview. + ### TODO -- [ ] Add support for more package managers -- [ ] Improve error handling -- [ ] Enhance return values and status codes +- [ ] Add brew support for macOS +- [ ] Add chocolatey/scoop/winget support for Windows +- [ ] Add support for more Linux package managers (dnf, apk, zypper) +- [ ] Implement Docker-based testing for multi-OS validation +- [ ] Improve error handling and status codes ## Contributing @@ -142,4 +205,4 @@ We welcome contributions to Go-SysPkg! Please read our [CONTRIBUTING.md](CONTRIB ## License -This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. +This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details. diff --git a/cmd/syspkg/main.go b/cmd/syspkg/main.go index 29e768e..fb10204 100644 --- a/cmd/syspkg/main.go +++ b/cmd/syspkg/main.go @@ -22,11 +22,9 @@ func main() { } // Initialize syspkg and find available package managers. - s, err := syspkg.New( - syspkg.IncludeOptions(syspkg.IncludeOptions{ - AllAvailable: true, - }), - ) + s, err := syspkg.New(syspkg.IncludeOptions{ + AllAvailable: true, + }) if err != nil { fmt.Printf("Error while initializing syspkg: %+v\n", err) os.Exit(1) diff --git a/go.mod b/go.mod index 4c20cb0..b73dd73 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/bluet/syspkg -go 1.21 +go 1.23 require github.com/urfave/cli/v2 v2.27.6 // direct diff --git a/manager/apt/apt.go b/manager/apt/apt.go index 163ac29..8a7cf80 100644 --- a/manager/apt/apt.go +++ b/manager/apt/apt.go @@ -18,6 +18,7 @@ import ( "log" "os" "os/exec" + "strings" // "github.com/rs/zerolog" // "github.com/rs/zerolog/log" @@ -46,9 +47,36 @@ var ENV_NonInteractive []string = []string{"LC_ALL=C", "DEBIAN_FRONTEND=noninter type PackageManager struct{} // IsAvailable checks if the apt package manager is available on the system. +// It verifies both that apt exists and that it's the Debian apt package manager +// (not the Java Annotation Processing Tool with the same name on some systems). func (a *PackageManager) IsAvailable() bool { + // First check if apt command exists _, err := exec.LookPath(pm) - return err == nil + if err != nil { + return false + } + + // Verify it's the Debian apt by checking for dpkg (Debian package manager) + _, dpkgErr := exec.LookPath("dpkg") + if dpkgErr != nil { + return false + } + + // Test if this is actually functional Debian apt by trying a safe command + // This approach: if apt+dpkg work together, support them regardless of platform + cmd := exec.Command("apt", "--version") + output, err := cmd.Output() + if err != nil { + return false + } + + // Verify the output looks like Debian apt (not Java apt) + outputStr := string(output) + // Debian apt version output typically contains "apt" and version info + // Java apt would have very different output + return len(outputStr) > 0 && + strings.Contains(strings.ToLower(outputStr), "apt") && + !strings.Contains(strings.ToLower(outputStr), "java") } // GetPackageManager returns the name of the apt package manager. diff --git a/manager/apt/utils.go b/manager/apt/utils.go index ab1a203..05f0685 100644 --- a/manager/apt/utils.go +++ b/manager/apt/utils.go @@ -8,6 +8,7 @@ import ( "log" "os/exec" "regexp" + "sort" "strings" // "github.com/rs/zerolog" @@ -158,7 +159,7 @@ func ParseFindOutput(msg string, opts *manager.Options) []manager.PackageInfo { packageInfo := manager.PackageInfo{ Name: strings.Split(parts[0], "/")[0], - Version: parts[1], + Version: "", NewVersion: parts[1], Category: strings.Split(parts[0], "/")[1], Arch: parts[2], @@ -284,6 +285,9 @@ func getPackageStatus(packages map[string]manager.PackageInfo) ([]manager.Packag packageNames = append(packageNames, name) } + // Sort package names to ensure deterministic output order + sort.Strings(packageNames) + args := []string{"-W", "--showformat", "${binary:Package} ${Status} ${Version}\n"} args = append(args, packageNames...) cmd := exec.Command("dpkg-query", args...) diff --git a/syspkg.go b/syspkg.go index a86d07c..12348cf 100644 --- a/syspkg.go +++ b/syspkg.go @@ -14,7 +14,7 @@ // if err != nil { // log.Fatal(err) // } -// aptManager,err := sysPkg.GetPackageManager("apt") +// aptManager, err := sysPkg.GetPackageManager("apt") package syspkg import ( @@ -99,9 +99,7 @@ func (s *sysPkgImpl) FindPackageManagers(include IncludeOptions) (map[string]Pac // GetPackageManager returns a PackageManager instance by its name (e.g., "apt", "snap", "flatpak", etc.). // if name is empty, return the first available -func (s *sysPkgImpl) GetPackageManager(name string) (PackageManager,error) { - var pm PackageManager - +func (s *sysPkgImpl) GetPackageManager(name string) (PackageManager, error) { // if there are no package managers, return before accessing non existing properties if len(s.pms) == 0 { return nil, errors.New("no supported package manager detected") @@ -114,12 +112,12 @@ func (s *sysPkgImpl) GetPackageManager(name string) (PackageManager,error) { keys = append(keys, k) } sort.Strings(keys) - pm = s.pms[keys[0]] - } else { - pm,found := s.pms[name] - if !found { - return pm, errors.New("no such package manager") - } + return s.pms[keys[0]], nil + } + + pm, found := s.pms[name] + if !found { + return nil, errors.New("no such package manager") } return pm, nil } diff --git a/syspkg_test.go b/syspkg_test.go index d3c540c..27a6a4f 100644 --- a/syspkg_test.go +++ b/syspkg_test.go @@ -53,107 +53,92 @@ func TestNewPackageManager(t *testing.T) { // if we are on any other distro, we should have nothing if OSInfo.Distribution == "ubuntu" || OSInfo.Distribution == "debian" || OSInfo.Distribution == "mint" || OSInfo.Distribution == "PopOS" || OSInfo.Distribution == "elementary" || OSInfo.Distribution == "Zorin" || OSInfo.Distribution == "ChromeOS" { - pm,err:=s.GetPackageManager("apt") + pm, err := s.GetPackageManager("apt") if err != nil && pm == nil { - pm,err:=s.GetPackageManager("snap") + pm, err := s.GetPackageManager("snap") - if err!=nil && pm == nil { - pm,err:=s.GetPackageManager("flatpak") + if err != nil && pm == nil { + pm, err := s.GetPackageManager("flatpak") - if err!=nil && pm == nil { + if err != nil && pm == nil { t.Fatalf("apt, snap, or flatpak package manager not found") } } } } else if OSInfo.Distribution == "fedora" || OSInfo.Distribution == "centos" || OSInfo.Distribution == "rhel" || OSInfo.Distribution == "rockylinux" || OSInfo.Distribution == "almalinux" || OSInfo.Distribution == "amazon linux" || OSInfo.Distribution == "oracle linux" || OSInfo.Distribution == "scientific linux" || OSInfo.Distribution == "cloudlinux" { - pm,err:=s.GetPackageManager("dnf") + pm, err := s.GetPackageManager("dnf") if err != nil && pm == nil { - pm,err:=s.GetPackageManager("yum") + pm, err := s.GetPackageManager("yum") if err != nil && pm == nil { t.Fatalf("dnf or yum package manager not found") } } } else if OSInfo.Distribution == "opensuse" { - pm,err:=s.GetPackageManager("zypper") + pm, err := s.GetPackageManager("zypper") if err != nil && pm == nil { t.Fatalf("zypper package manager not found") } } else if OSInfo.Distribution == "alpine" { - pm,err:=s.GetPackageManager("apk") + pm, err := s.GetPackageManager("apk") if err != nil && pm == nil { t.Fatalf("apk package manager not found") } } else if OSInfo.Distribution == "arch" { - pm,err:=s.GetPackageManager("pacman") + pm, err := s.GetPackageManager("pacman") if err != nil && pm == nil { t.Fatalf("pacman package manager not found") } } else if OSInfo.Distribution == "gentoo" { - pm,err:=s.GetPackageManager("emerge") + pm, err := s.GetPackageManager("emerge") if err != nil && pm == nil { t.Fatalf("emerge package manager not found") } } else if OSInfo.Distribution == "slackware" { - pm,err:=s.GetPackageManager("slackpkg") + pm, err := s.GetPackageManager("slackpkg") if err != nil && pm == nil { t.Fatalf("slackpkg package manager not found") } } else if OSInfo.Distribution == "void" { - pm,err:=s.GetPackageManager("xbps") + pm, err := s.GetPackageManager("xbps") if err != nil && pm == nil { t.Fatalf("xbps package manager not found") } } else if OSInfo.Distribution == "solus" { - pm,err:=s.GetPackageManager("eopkg") + pm, err := s.GetPackageManager("eopkg") if err != nil && pm == nil { t.Fatalf("eopkg package manager not found") } } else if OSInfo.Distribution == "freebsd" || OSInfo.Distribution == "dragonfly" || OSInfo.Distribution == "termux" { - pm,err:=s.GetPackageManager("pkg") + pm, err := s.GetPackageManager("pkg") if err != nil && pm == nil { t.Fatalf("pkg package manager not found") } } else if OSInfo.Distribution == "openbsd" || OSInfo.Distribution == "netbsd" { - pm,err:=s.GetPackageManager("pkg_add") + pm, err := s.GetPackageManager("pkg_add") if err != nil && pm == nil { t.Fatalf("pkg_add package manager not found") } - } else if OSInfo.Distribution == "macos" { - pm,err:=s.GetPackageManager("brew") - if err != nil && pm == nil { - t.Fatalf("brew package manager not found") - } - } else if OSInfo.Distribution == "windows" { - pm,err:=s.GetPackageManager("chocolatey") - if err != nil && pm == nil { - pm,err:=s.GetPackageManager("scoop") - if err != nil && pm == nil { - pm,err:=s.GetPackageManager("winget") - if err != nil && pm == nil { - t.Fatalf("chocolatey, scoop, or winget package manager not found") - } - } - } - } else if OSInfo.Distribution == "android" { - pm,err:=s.GetPackageManager("f-droid") - if err != nil && pm == nil { - t.Fatalf("f-droid package manager not found") - } - } else if OSInfo.Distribution == "ios" { - pm,err:=s.GetPackageManager("cydia") - if err != nil && pm == nil { - t.Fatalf("cydia package manager not found") - } } else { - if len(pms) > 0 { - t.Fatalf("package manager found when none should be") - } else { - log.Printf("no package manager found, as expected") - } + // For other OSes (including macOS, Windows, etc.), we currently only support + // apt, flatpak, and snap. These may or may not be available on any given system. + // Just log what we found for debugging purposes. + log.Printf("Found %d package managers: %v", len(pms), getPackageManagerNames(pms)) + + // Don't fail the test - package manager availability varies by system + // and installation method (e.g., apt can be installed on macOS via Homebrew) } // if manager == nil { // t.Fatal("NewPackageManager() returned a nil manager") // } } + +// getPackageManagerNames returns a slice of package manager names from the map +func getPackageManagerNames(pms map[string]syspkg.PackageManager) []string { + names := make([]string, 0, len(pms)) + for name := range pms { + names = append(names, name) + } + return names +} diff --git a/testing/capture-fixtures.sh b/testing/capture-fixtures.sh new file mode 100755 index 0000000..506dcbf --- /dev/null +++ b/testing/capture-fixtures.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Script to capture real package manager outputs for test fixtures + +set -e + +FIXTURE_DIR="testing/fixtures" +mkdir -p "$FIXTURE_DIR"/{apt,snap,flatpak,dnf,apk} + +echo "Capturing package manager outputs for test fixtures..." + +# APT (if available) +if command -v apt &> /dev/null; then + echo "Capturing APT outputs..." + apt search vim 2>/dev/null | head -50 > "$FIXTURE_DIR/apt/search-vim.txt" || true + apt show vim 2>/dev/null > "$FIXTURE_DIR/apt/show-vim.txt" || true + dpkg -l | head -20 > "$FIXTURE_DIR/apt/list-installed.txt" || true + apt list --upgradable 2>/dev/null | head -20 > "$FIXTURE_DIR/apt/list-upgradable.txt" || true +fi + +# SNAP (if available) - requires real system with snapd running +if command -v snap &> /dev/null && systemctl is-active snapd &>/dev/null; then + echo "Capturing SNAP outputs..." + snap find vim 2>/dev/null | head -20 > "$FIXTURE_DIR/snap/find-vim.txt" || true + snap list 2>/dev/null > "$FIXTURE_DIR/snap/list.txt" || true + snap info core 2>/dev/null > "$FIXTURE_DIR/snap/info-core.txt" || true +else + echo "SNAP not available or snapd not running - using Docker for mock data" + # We can't get real snap outputs from Docker, so we'll document sample outputs + cat > "$FIXTURE_DIR/snap/find-vim.txt" << 'EOF' +Name Version Publisher Notes Summary +vim-editor 8.2.3995 jonathonf - Vi IMproved - enhanced vi editor +nvim 0.7.2 neovim - Vim-fork focused on extensibility +EOF + + cat > "$FIXTURE_DIR/snap/list.txt" << 'EOF' +Name Version Rev Tracking Publisher Notes +core20 20230801 2015 latest/stable canonicalโœ“ base +core22 20230801 864 latest/stable canonicalโœ“ base +snapd 2.60.3 20290 latest/stable canonicalโœ“ snapd +EOF +fi + +# FLATPAK (if available) +if command -v flatpak &> /dev/null; then + echo "Capturing FLATPAK outputs..." + flatpak search vim 2>/dev/null | head -20 > "$FIXTURE_DIR/flatpak/search-vim.txt" || true + flatpak list 2>/dev/null > "$FIXTURE_DIR/flatpak/list.txt" || true +fi + +echo "Fixture capture complete!" +echo "You can now use these files in your tests:" +find "$FIXTURE_DIR" -type f -name "*.txt" | sort diff --git a/testing/docker/README.md b/testing/docker/README.md new file mode 100644 index 0000000..ebe8d07 --- /dev/null +++ b/testing/docker/README.md @@ -0,0 +1,179 @@ +# Docker-Based Testing Strategy + +## Overview + +This directory contains Docker configurations for testing go-syspkg across multiple Linux distributions. + +## Test Categories + +### 1. Unit Tests (Run Everywhere) +- Parser functions with captured outputs +- OS detection logic +- Command construction +- No actual package manager execution + +### 2. Integration Tests (Container-Specific) +- Real package manager availability checks +- Command output capture for test fixtures +- Limited package operations (list, search) + +### 3. Full System Tests (Native CI Only) +- Actual package installation/removal +- Privileged operations +- Snap/systemd dependent features + +## Docker Test Structure (Planned) + +**Note:** The docker-compose.test.yml file is planned for future implementation. This shows the intended structure. + +```yaml +# Planned: docker-compose.test.yml +version: '3.8' + +services: + ubuntu-test: + build: + context: ../.. + dockerfile: testing/docker/ubuntu.Dockerfile + environment: + - IN_CONTAINER=true + - TEST_TAGS=unit,parser + volumes: + - ../..:/workspace + working_dir: /workspace + command: go test -tags="unit parser" ./... + + debian-test: + build: + context: ../.. + dockerfile: testing/docker/debian.Dockerfile + environment: + - IN_CONTAINER=true + - TEST_TAGS=unit,parser + volumes: + - ../..:/workspace + working_dir: /workspace + command: go test -tags="unit parser" ./... + + fedora-test: + build: + context: ../.. + dockerfile: testing/docker/fedora.Dockerfile + environment: + - IN_CONTAINER=true + - TEST_TAGS=unit,parser + volumes: + - ../..:/workspace + working_dir: /workspace + command: go test -tags="unit parser" ./... + + alpine-test: + build: + context: ../.. + dockerfile: testing/docker/alpine.Dockerfile + environment: + - IN_CONTAINER=true + - TEST_TAGS=unit,parser + volumes: + - ../..:/workspace + working_dir: /workspace + command: go test -tags="unit parser" ./... +``` + +## Usage + +**Note:** These Docker testing targets are planned for future implementation. Currently, the project tests on Ubuntu in CI/CD. + +### Planned: Run All Container Tests +```bash +# TODO: Implement when Makefile targets are added +make test-docker-all +``` + +### Planned: Run Specific OS Test +```bash +# TODO: Implement when docker-compose.test.yml is created +docker-compose -f docker-compose.test.yml run ubuntu-test +``` + +### Capture Test Fixtures +```bash +# Run container interactively to capture package manager outputs +docker-compose -f docker-compose.test.yml run --rm ubuntu-test bash +apt update +apt search vim > testing/fixtures/apt/search-vim.txt +``` + +## Test Implementation Example + +```go +// +build parser + +package apt_test + +import ( + "os" + "os/exec" + "testing" + + "github.com/bluet/syspkg/manager/apt" +) + +func TestParseSearchOutput_MultiOS(t *testing.T) { + // Skip if not in container + if os.Getenv("IN_CONTAINER") != "true" { + t.Skip("Skipping container-only test") + } + + // Test with real apt output from this OS version + output, err := exec.Command("apt", "search", "vim").Output() + if err != nil { + t.Skip("apt not available in this container") + } + + packages := apt.ParseSearchOutput(string(output)) + + // Verify parsing works for this OS version + if len(packages) == 0 { + t.Error("Expected to parse some packages") + } +} +``` + +## CI Integration (Planned) + +**Note:** This is a planned feature for multi-OS Docker testing. Currently, the project uses `.github/workflows/test.yml` for Ubuntu-based testing. + +```yaml +# Planned: .github/workflows/multi-os-test.yml +name: Multi-OS Docker Tests + +on: [push, pull_request] + +jobs: + docker-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Run Docker Tests + run: | + # TODO: Create docker-compose.test.yml before enabling + docker-compose -f testing/docker/docker-compose.test.yml up \ + --abort-on-container-exit \ + --exit-code-from ubuntu-test + + - name: Upload Test Results + uses: actions/upload-artifact@v3 + with: + name: test-results + path: test-results/ # TODO: Ensure tests output to this directory +``` + +## Best Practices + +1. **Keep Images Minimal**: Install only what's required for testing +2. **Cache Aggressively**: Use Docker layer caching +3. **Parallelize Tests**: Run different OS tests concurrently +4. **Mock External Calls**: Don't actually install packages in tests +5. **Capture Real Outputs**: Use containers to generate test fixtures diff --git a/testing/docker/alpine.Dockerfile b/testing/docker/alpine.Dockerfile new file mode 100644 index 0000000..19d063b --- /dev/null +++ b/testing/docker/alpine.Dockerfile @@ -0,0 +1,24 @@ +# Alpine test container for go-syspkg +FROM alpine:3.18 + +# Install build dependencies and apk package manager +RUN apk add --no-cache \ + go \ + git \ + make \ + alpine-sdk \ + bash + +# Set working directory +WORKDIR /workspace + +# Install test dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Set test environment +ENV IN_CONTAINER=true +ENV CGO_ENABLED=0 + +# Default command runs tests +CMD ["go", "test", "-v", "./..."] diff --git a/testing/docker/test-strategy.md b/testing/docker/test-strategy.md new file mode 100644 index 0000000..23b9c58 --- /dev/null +++ b/testing/docker/test-strategy.md @@ -0,0 +1,173 @@ +# Docker Testing Strategy for Package Managers + +## What Works Well in Docker + +### โœ… APT Testing +```bash +docker run --rm -v $(PWD):/workspace ubuntu:22.04 bash -c " + apt update + apt search vim | head -20 > /workspace/testing/fixtures/apt/search-output.txt + apt show vim > /workspace/testing/fixtures/apt/show-output.txt + dpkg -l | head -20 > /workspace/testing/fixtures/apt/list-output.txt +" +``` + +### โœ… DNF/YUM Testing (Fedora) +```bash +docker run --rm -v $(PWD):/workspace fedora:38 bash -c " + dnf search vim | head -20 > /workspace/testing/fixtures/dnf/search-output.txt + dnf info vim > /workspace/testing/fixtures/dnf/info-output.txt +" +``` + +### โœ… APK Testing (Alpine) +```bash +docker run --rm -v $(PWD):/workspace alpine:3.18 sh -c " + apk search vim > /workspace/testing/fixtures/apk/search-output.txt + apk info vim > /workspace/testing/fixtures/apk/info-output.txt +" +``` + +### โœ… Flatpak Testing (Limited) +```bash +# Flatpak can list/search without full functionality +docker run --rm -v $(PWD):/workspace ubuntu:22.04 bash -c " + apt update && apt install -y flatpak + flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + flatpak search vim > /workspace/testing/fixtures/flatpak/search-output.txt || true +" +``` + +## What Doesn't Work in Docker + +### โŒ Snap Operations +- `snap install/remove` - Requires snapd daemon +- `snap list` - Requires running snapd +- `snap find` - Requires snapd connection + +### โŒ System Package Installation +- Installing actual packages (without --privileged) +- System-level operations +- Hardware access + +## Recommended Test Approach + +### 1. **Docker for Fixture Generation** +Use Docker to generate real command outputs: + +```go +//go:generate docker run --rm -v $(PWD):/workspace ubuntu:22.04 bash -c "apt update && apt search vim > /workspace/testing/fixtures/apt/search-vim.txt" +``` + +### 2. **Mock Testing for CI** +```go +// +build !integration + +func TestAptInstall(t *testing.T) { + executor := &MockExecutor{ + outputs: map[string]string{ + "apt install -y vim": readFixture("apt/install-vim.txt"), + }, + } + + pm := apt.NewWithExecutor(executor) + packages, err := pm.Install([]string{"vim"}, &manager.Options{AssumeYes: true}) + + assert.NoError(t, err) + assert.Len(t, packages, 1) +} +``` + +### 3. **Integration Testing Matrix** +```yaml +# .github/workflows/integration.yml +jobs: + apt-test: + runs-on: ubuntu-latest + steps: + - run: | + sudo apt update + sudo apt install -y vim + go test -tags=integration ./manager/apt + + snap-test: + runs-on: ubuntu-latest + steps: + - run: | + sudo snap install hello-world + go test -tags=integration ./manager/snap + + flatpak-test: + runs-on: ubuntu-latest + steps: + - run: | + sudo apt install -y flatpak + go test -tags=integration ./manager/flatpak +``` + +## Docker Test Implementation + +### Base Test Runner +```go +package testing + +import ( + "context" + "fmt" + "os" + "os/exec" + "time" +) + +type DockerTestRunner struct { + Image string + Cmd string + Timeout time.Duration +} + +func (d *DockerTestRunner) CaptureOutput(outputFile string) error { + timeout := d.Timeout + if timeout == 0 { + timeout = 30 * time.Second + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + workDir, err := os.Getwd() + if err != nil { + return fmt.Errorf("failed to get working directory: %w", err) + } + + cmd := exec.CommandContext(ctx, "docker", "run", "--rm", + "-v", fmt.Sprintf("%s:/workspace", workDir), + d.Image, + "bash", "-c", d.Cmd + " > /workspace/" + outputFile) + + return cmd.Run() +} +``` + +### Usage in Tests +```go +func TestCaptureRealOutputs(t *testing.T) { + if os.Getenv("CAPTURE_FIXTURES") != "true" { + t.Skip("Skipping fixture capture") + } + + runner := &DockerTestRunner{ + Image: "ubuntu:22.04", + Cmd: "apt update && apt search golang", + Timeout: 60 * time.Second, // Optional: defaults to 30s + } + + err := runner.CaptureOutput("testing/fixtures/apt/search-golang.txt") + assert.NoError(t, err) +} +``` + +## Summary + +- **Use Docker for**: Capturing real outputs, testing parsers, OS detection +- **Don't use Docker for**: snap operations, actual installations, privileged operations +- **Alternative for snap**: Mock data or native CI runners diff --git a/testing/docker/ubuntu.Dockerfile b/testing/docker/ubuntu.Dockerfile new file mode 100644 index 0000000..365a12f --- /dev/null +++ b/testing/docker/ubuntu.Dockerfile @@ -0,0 +1,39 @@ +# Ubuntu test container for go-syspkg +FROM ubuntu:22.04 + +# Avoid interactive prompts +ENV DEBIAN_FRONTEND=noninteractive + +# Install package managers and dependencies +RUN apt-get update && apt-get install -y \ + apt-utils \ + software-properties-common \ + flatpak \ + curl \ + git \ + make \ + && rm -rf /var/lib/apt/lists/* + +# Install Go +RUN curl -L https://go.dev/dl/go1.21.0.linux-amd64.tar.gz | tar -C /usr/local -xz +ENV PATH="/usr/local/go/bin:${PATH}" + +# Note: snap requires systemd which doesn't work in standard Docker containers +# Options for snap testing: +# 1. Use mock data for snap command outputs +# 2. Use GitHub Actions with native Ubuntu runners +# 3. Use systemd-enabled containers (complex setup) + +# Set working directory +WORKDIR /workspace + +# Install test dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Set test environment +ENV IN_CONTAINER=true +ENV CGO_ENABLED=0 + +# Default command runs tests +CMD ["go", "test", "-v", "./..."] diff --git a/testing/fixtures/apt/list-installed.txt b/testing/fixtures/apt/list-installed.txt new file mode 100644 index 0000000..1549560 --- /dev/null +++ b/testing/fixtures/apt/list-installed.txt @@ -0,0 +1,20 @@ +่ฆๆฑ‚=U:ๆœช็Ÿฅ/I:ๅฎ‰่ฃ/R:ๅˆช้™ค/P:ๆธ…้™ค/H:ไฟ็•™ +| ็‹€ๆ…‹=N:ๆœชๅฎ‰่ฃ/I:ๅทฒๅฎ‰่ฃ/C:่จญๅฎšๆช”/U:ๅทฒ่งฃ้–‹/F:ๅŠ่จญๅฎš/H:ๅŠๅฎ‰่ฃ/W:ๅพ…่งธ็™ผ/T:ๆœช่งธ็™ผ +|/ ้Œฏ่ชค?=(็„ก)/R:้ ˆ้‡ๆ–ฐๅฎ‰่ฃ๏ผˆ็‹€ๆ…‹๏ผŒ้Œฏ่ชค๏ผšๅคงๅฏซ=ๆœ‰ๅ•้กŒ๏ผ‰ +||/ ๅ็จฑ ็‰ˆๆœฌ ็กฌ้ซ”ๅนณๅฐ ็ฐกไป‹ ++++-==========================================-================================================================-============-=========================================================================================================================================================================================================================================================================================================================================================================================================================================== +ii accountsservice 22.07.5-2ubuntu1.5 amd64 query and manipulate user account information +ii acl 2.3.1-1 amd64 access control list - utilities +ii acpi-support 0.144 amd64 scripts for handling many ACPI events +ii acpid 1:2.0.33-1ubuntu1 amd64 Advanced Configuration and Power Interface event daemon +ii adb 1:10.0.0+r36-9 amd64 Android Debug Bridge +ii adduser 3.118ubuntu5 all add and remove users and groups +ii adium-theme-ubuntu 0.3.4-0ubuntu4 all Adium message style for Ubuntu +ii adwaita-icon-theme 41.0-1ubuntu1 all default icon theme of GNOME (small subset) +ii adwaita-icon-theme-full 41.0-1ubuntu1 all default icon theme of GNOME +ii aisleriot 1:3.22.22-1 amd64 GNOME solitaire card game collection +ii alsa-base 1.0.25+dfsg-0ubuntu7 all ALSA driver configuration files +ii alsa-topology-conf 1.2.5.1-2 all ALSA topology configuration files +ii alsa-ucm-conf 1.2.6.3-1ubuntu1.12 all ALSA Use Case Manager configuration files +ii alsa-utils 1.2.6-1ubuntu1 amd64 Utilities for configuring and using ALSA +ii amd64-microcode 3.20191218.1ubuntu2.3 amd64 Processor microcode firmware for AMD CPUs diff --git a/testing/fixtures/apt/list-upgradable.txt b/testing/fixtures/apt/list-upgradable.txt new file mode 100644 index 0000000..b3e0f4b --- /dev/null +++ b/testing/fixtures/apt/list-upgradable.txt @@ -0,0 +1,10 @@ +ๆญฃๅœจๅˆ—ๅ‡บ... +apt-transport-https/jammy-updates,jammy-updates 2.4.14 all [ๅฏๅ‡็ดš่‡ช๏ผš2.4.13] +apt-utils/jammy-updates 2.4.14 amd64 [ๅฏๅ‡็ดš่‡ช๏ผš2.4.13] +apt/jammy-updates 2.4.14 amd64 [ๅฏๅ‡็ดš่‡ช๏ผš2.4.13] +chrome-remote-desktop/stable 137.0.7151.0 amd64 [ๅฏๅ‡็ดš่‡ช๏ผš136.0.7103.19] +initramfs-tools-bin/jammy-updates 0.140ubuntu13.5 amd64 [ๅฏๅ‡็ดš่‡ช๏ผš0.140ubuntu13.4] +initramfs-tools-core/jammy-updates,jammy-updates 0.140ubuntu13.5 all [ๅฏๅ‡็ดš่‡ช๏ผš0.140ubuntu13.4] +initramfs-tools/jammy-updates,jammy-updates 0.140ubuntu13.5 all [ๅฏๅ‡็ดš่‡ช๏ผš0.140ubuntu13.4] +libapt-pkg6.0/jammy-updates 2.4.14 amd64 [ๅฏๅ‡็ดš่‡ช๏ผš2.4.13] +opera-stable/stable 119.0.5497.56 amd64 [ๅฏๅ‡็ดš่‡ช๏ผš119.0.5497.52] diff --git a/testing/fixtures/apt/search-vim.txt b/testing/fixtures/apt/search-vim.txt new file mode 100644 index 0000000..6688b1c --- /dev/null +++ b/testing/fixtures/apt/search-vim.txt @@ -0,0 +1,49 @@ +ๆŽ’ๅบ... +ๅ…จๆ–‡ๆœๅฐ‹... +acr/jammy,jammy 1.9.4-1 all + autoconf like tool + +alot/jammy,jammy 0.10-1 all + Text mode MUA using notmuch mail + +alot-doc/jammy,jammy 0.10-1 all + Text mode MUA using notmuch mail - documentation + +apvlv/jammy 0.4.0-2 amd64 + PDF viewer with Vim-like behaviour + +biosyntax-vim/jammy,jammy 1.0.0b-2 all + Syntax Highlighting for Computational Biology (vim) + +bleachbit/jammy,jammy 4.4.2-1 all + delete unnecessary files from the system + +bombadillo/jammy-updates,jammy-security 2.3.3-3ubuntu0.1 amd64 + Non-web client for the terminal + +clang-format-11/jammy 1:11.1.0-6 amd64 + Tool to format C/C++/Obj-C code + +clang-format-12/jammy 1:12.0.1-19ubuntu3 amd64 + Tool to format C/C++/Obj-C code + +clang-format-13/jammy-updates,jammy-security 1:13.0.1-2ubuntu2.2 amd64 + Tool to format C/C++/Obj-C code + +clang-format-14/jammy-updates,jammy-security 1:14.0.0-1ubuntu1.1 amd64 + Tool to format C/C++/Obj-C code + +clang-format-15/jammy-updates,jammy-security 1:15.0.7-0ubuntu0.22.04.3 amd64 + Tool to format C/C++/Obj-C code + +clang-format-18/ไธๆ˜Ž 1:18.1.8~++20240731024944+3b5b5c1ec4a3-1~exp1~20240731145000.144 amd64 + Tool to format C/C++/Obj-C code + +colordiff/jammy,jammy 1.0.18-1.1 all + tool to colorize 'diff' output + +context-modules/jammy,jammy 20210301-1 all + additional ConTeXt modules + +copyq/jammy 6.0.1-1 amd64 + Advanced clipboard manager with editing and scripting features diff --git a/testing/fixtures/apt/show-vim.txt b/testing/fixtures/apt/show-vim.txt new file mode 100644 index 0000000..b23b01a --- /dev/null +++ b/testing/fixtures/apt/show-vim.txt @@ -0,0 +1,28 @@ +Package: vim +Version: 2:8.2.3995-1ubuntu2.24 +Priority: optional +Section: editors +Origin: Ubuntu +Maintainer: Ubuntu Developers +Original-Maintainer: Debian Vim Maintainers +Bugs: https://bugs.launchpad.net/ubuntu/+filebug +Installed-Size: 4,025 kB +Provides: editor +Depends: vim-common (= 2:8.2.3995-1ubuntu2.24), vim-runtime (= 2:8.2.3995-1ubuntu2.24), libacl1 (>= 2.2.23), libc6 (>= 2.34), libgpm2 (>= 1.20.7), libpython3.10 (>= 3.10.0), libselinux1 (>= 3.1~), libsodium23 (>= 1.0.14), libtinfo6 (>= 6) +Suggests: ctags, vim-doc, vim-scripts +Homepage: https://www.vim.org/ +Task: cloud-image, ubuntu-wsl, server, ubuntu-server-raspi, lubuntu-desktop +Download-Size: 1,728 kB +APT-Manual-Installed: yes +APT-Sources: http://ftp.ubuntu-tw.net/ubuntu jammy-updates/main amd64 Packages +Description: Vi IMproved - enhanced vi editor + Vim is an almost compatible version of the UNIX editor Vi. + . + Many new features have been added: multi level undo, syntax + highlighting, command line history, on-line help, filename + completion, block operations, folding, Unicode support, etc. + . + This package contains a version of vim compiled with a rather + standard set of features. This package does not provide a GUI + version of Vim. See the other vim-* packages if you need more + (or less). diff --git a/testing/fixtures/flatpak/list.txt b/testing/fixtures/flatpak/list.txt new file mode 100644 index 0000000..f86bf4b --- /dev/null +++ b/testing/fixtures/flatpak/list.txt @@ -0,0 +1,70 @@ +Vorta contributors com.borgbase.Vorta v0.10.3 stable system +John Factotum com.github.johnfactotum.Foliate 3.3.0 stable system +JetBrains s.r.o. com.jetbrains.DataGrip 2025.1.3 stable system +ๆ“ดๅ……ๅŠŸ่ƒฝ็ฎก็†ๅ“ก com.mattjakeman.ExtensionManager 0.6.3 stable system +Slack Technologies Inc. com.slack.Slack 4.43.52 stable system +The Bottles Contributors com.usebottles.bottles 51.21 stable system +Freedesktop SDK org.freedesktop.Platform freedesktop-sdk-23.08.31 23.08 system +Freedesktop SDK org.freedesktop.Platform freedesktop-sdk-24.08.19 24.08 system +Freedesktop SDK org.freedesktop.Platform.GL.default 25.0.5 23.08 system +Freedesktop SDK org.freedesktop.Platform.GL.default 25.0.5 23.08-extra system +Freedesktop SDK org.freedesktop.Platform.GL.default 25.0.5 24.08 system +Freedesktop SDK org.freedesktop.Platform.GL.default 25.0.5 24.08extra system +Freedesktop SDK org.freedesktop.Platform.GL32.default 25.0.5 23.08 system +Freedesktop SDK org.freedesktop.Platform.GL32.default 25.0.5 24.08 system +Freedesktop SDK org.freedesktop.Platform.VAAPI.Intel 23.08 system +Freedesktop SDK org.freedesktop.Platform.VAAPI.Intel 24.08 system +Freedesktop SDK org.freedesktop.Platform.ffmpeg-full 23.08 system +Freedesktop SDK org.freedesktop.Platform.ffmpeg-full 24.08 system +i386 org.freedesktop.Platform.ffmpeg_full.i386 23.08 system +i386 org.freedesktop.Platform.ffmpeg_full.i386 24.08 system +openh264 org.freedesktop.Platform.openh264 2.1.0 2.0 system +openh264 org.freedesktop.Platform.openh264 2.1.0 2.2.0 system +openh264 org.freedesktop.Platform.openh264 2.1.0 2.3.0 system +openh264 org.freedesktop.Platform.openh264 2.4.1 2.4.1 system +Cisco Systems, Inc. org.freedesktop.Platform.openh264 2.5.1 2.5.1 system +Freedesktop SDK org.freedesktop.Sdk freedesktop-sdk-23.08.31 23.08 system +Freedesktop SDK org.freedesktop.Sdk freedesktop-sdk-24.08.19 24.08 system +GNOME Application Platform version 47 org.gnome.Platform 47 system +GNOME Application Platform version 48 org.gnome.Platform 48 system +i386 org.gnome.Platform.Compat.i386 47 system +Ambiance Gtk theme org.gtk.Gtk3theme.Ambiance 3.22 system +Yaru Gtk Theme org.gtk.Gtk3theme.Yaru 3.22 system +Adwaita theme org.kde.KStyle.Adwaita 5.15-21.08 system +Adwaita theme org.kde.KStyle.Adwaita 5.15-22.08 system +Adwaita theme org.kde.KStyle.Adwaita 5.15-23.08 system +Adwaita theme org.kde.KStyle.Adwaita 6.4 system +Adwaita theme org.kde.KStyle.Adwaita 6.6 system +KDE Application Platform org.kde.Platform 5.15-24.08 system +KDE Application Platform org.kde.Platform 6.7 system +KDE Application Platform org.kde.Platform 6.8 system +KDE Application Platform org.kde.Platform 6.9 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 5.15 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 5.15-21.08 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 5.15-22.08 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 5.15-23.08 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 5.15-24.08 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 6.4 system +QGnomePlatform org.kde.PlatformTheme.QGnomePlatform 6.6 system +QtSNI org.kde.PlatformTheme.QtSNI 5.15 system +QAdwaitaDecorations org.kde.WaylandDecoration.QAdwaitaDecorations 5.15-22.08 system +QAdwaitaDecorations org.kde.WaylandDecoration.QAdwaitaDecorations 5.15-23.08 system +QAdwaitaDecorations org.kde.WaylandDecoration.QAdwaitaDecorations 5.15-24.08 system +QAdwaitaDecorations org.kde.WaylandDecoration.QAdwaitaDecorations 6.6 system +QAdwaitaDecorations org.kde.WaylandDecoration.QAdwaitaDecorations 6.7 system +QGnomePlatform-decoration org.kde.WaylandDecoration.QGnomePlatform-decoration 5.14 system +QGnomePlatform-decoration org.kde.WaylandDecoration.QGnomePlatform-decoration 5.15 system +QGnomePlatform-decoration org.kde.WaylandDecoration.QGnomePlatform-decoration 5.15-21.08 system +QGnomePlatform-decoration org.kde.WaylandDecoration.QGnomePlatform-decoration 5.15-22.08 system +QGnomePlatform-decoration org.kde.WaylandDecoration.QGnomePlatform-decoration 5.15-23.08 system +QGnomePlatform-decoration org.kde.WaylandDecoration.QGnomePlatform-decoration 6.4 system +QGnomePlatform_decoration sourcecode org.kde.WaylandDecoration.QGnomePlatform_decoration.Sources 5.14 system +Tor Project org.torproject.torbrowser-launcher 0.3.7 stable system +DXVK org.winehq.Wine.DLLs.dxvk 2.3.1 stable-22.08 system +DXVK org.winehq.Wine.DLLs.dxvk 2.4.1 stable-23.08 system +Gecko org.winehq.Wine.gecko stable-22.08 system +Gecko org.winehq.Wine.gecko stable-23.08 system +gecko org.winehq.Wine.gecko stable-24.08 system +Mono org.winehq.Wine.mono stable-22.08 system +Mono org.winehq.Wine.mono stable-23.08 system +mono org.winehq.Wine.mono stable-24.08 system diff --git a/testing/fixtures/flatpak/search-vim.txt b/testing/fixtures/flatpak/search-vim.txt new file mode 100644 index 0000000..1c58579 --- /dev/null +++ b/testing/fixtures/flatpak/search-vim.txt @@ -0,0 +1,12 @@ +Vim The ubiquitous text editor org.vim.Vim v9.1.1355-4-gf57c065e7 stable flathub +Vimix Video live mixer io.github.brunoherbelin.Vimix 0.8.4 stable flathub +AVI MetaEdit Embed, validate, and export AVI files metadata net.mediaarea.AVIMetaEdit 1.0.2 stable flathub +Neovim Vim-fork focused on extensibility and usability io.neovim.nvim 0.11.1 stable flathub +Vieb Vim Inspired Electron Browser dev.vieb.Vieb 12.3.0 stable flathub +iamb A terminal Matrix client for Vim addicts chat.iamb.iamb 0.0.10 stable flathub +Devhelp ็€่ฆฝ่ˆ‡ๆœๅฐ‹ API ๆ–‡ไปถ็š„้–‹็™ผ่€…ๅทฅๅ…ท org.gnome.Devhelp 43.0 stable flathub +Builder Create applications for GNOME org.gnome.Builder 48.0 stable flathub +Formiko reStructuredText and MarkDown editor cz.zeropage.Formiko 1.5.0 stable flathub +Communique RSS Reader with cross-platform sync com.github.suzie97.communique 1.1.0 stable flathub +qutebrowser A keyboard-driven web browser org.qutebrowser.qutebrowser 2.5.4 stable flathub +4KTUBE 4K YouTube Downloader โ€“ Download HD YouTube Videos, Playlists, and Music Instantly. com.warlordsoftwares.youtube-downloader-4ktube 2025.5.23 stable flathub diff --git a/testing/fixtures/snap/find-vim.txt b/testing/fixtures/snap/find-vim.txt new file mode 100644 index 0000000..5f804bf --- /dev/null +++ b/testing/fixtures/snap/find-vim.txt @@ -0,0 +1,20 @@ +Name Version Publisher Notes Summary +vim-language-server 2.3.1 alexmurray* - VimScript Language Server +vimix-themes 2020-02-24-15-g426d7e0 gantonayde - Vimix GTK and Icon Themes for GTK Snaps +vim-editor 8.2.788 zilongzhaobur - vim, the text editor +vimix 0.8.4 bruno-herbelin - Video live mixer +vim-deb 0.1 bugwolf - A deb package for vim. +clion 2025.1.1 jetbrains** classic A cross-platform IDE for C and C++ +helix 25.01.1 lauren-brock classic Helix is a modal text editor inspired by Vim and Kakoune +iamb v0.0.10 popey* - A Matrix client for Vim addicts +ncspot 1.2.2 popey* - Cross-platform ncurses Spotify client written in Rust +plumber 3.1 keshavnrj* - Media trimmer/downloader for Linux Desktop +neovim-kalikiana 0.1.4 kalikiana - Vim-fork focused on extensibility and agility. +chromeos-themes 2020-01-18-25-g765be0e gantonayde - ChromeOS GTK Themes for GTK Snaps +nvim v0.11.1 neovim-snap classic Vim-fork focused on extensibility and usability +kakoune v2023.08.05 lukewh classic Modal editor +neovide 0.8.0+git j4qfrost - The snappiest vim editor you are likely to find. +yazi v25.5.28 sxyazi classic ๐Ÿ’ฅ Blazing fast terminal file manager written in Rust, based on async I/O. +sudoku-rs 1.1 mitchel0022 - Sudoku right in the terminal +4ktube 2025.5.23 rishabh3354 - YouTube Video Downloader ๐Ÿš€ +libretextus 0.2 npscript42 - Simple Bible Utility diff --git a/testing/fixtures/snap/info-core.txt b/testing/fixtures/snap/info-core.txt new file mode 100644 index 0000000..b7a8eb8 --- /dev/null +++ b/testing/fixtures/snap/info-core.txt @@ -0,0 +1,51 @@ +name: core +summary: Snap runtime environment +publisher: Canonical** +store-url: https://snapcraft.io/core +license: unset +description: | + Base snaps are a specific type of snap that include libraries and + dependencies common to many applications. They provide a consistent and + reliable execution environment for the snap packages that use them. + + This core base snap additionally includes the snapd binaries, which in + later releases are installed separately as the snapd snap. For more details + on the snapd snap, see https://snapcraft.io/snapd. + + The core base snap provides a runtime environment based on Ubuntu 16.04 ESM + (Xenial Xerus). + + Other Ubuntu environment base snaps include: + - Core 18: + - Core 20: + - Core 22: + - Core 24: + + **Using a base snap** + + Base snaps are installed automatically when a snap package requires them. + Only one of each type of base snap is ever installed. + + Manually removing a base snap may affect the stability of your system. + + **Building snaps with core** + + Snap developers can use this base in their own snaps by adding the + following to the snap's snapcraft.yaml: + + base: core + + **Additional Information*** + + For more details, and guidance on using base snaps, see our documentation: + +type: core +snap-id: 99T7MUlRhtI3U0QFgl5mXXESAiSwt776 +tracking: latest/stable +refresh-date: 22 days ago, at 18:37 CST +channels: + latest/stable: 16-2.61.4-20241002 2025-05-09 (17210) 109MB - + latest/candidate: 16-2.61.4-20241002 2025-05-06 (17210) 109MB - + latest/beta: 16-2.61.4-20250508 2025-05-08 (17212) 109MB - + latest/edge: 16-2.61.4-20250529 2025-05-29 (17230) 109MB - +installed: 16-2.61.4-20241002 (17210) 109MB core diff --git a/testing/fixtures/snap/list.txt b/testing/fixtures/snap/list.txt new file mode 100644 index 0000000..79ddec8 --- /dev/null +++ b/testing/fixtures/snap/list.txt @@ -0,0 +1,40 @@ +Name Version Rev Tracking Publisher Notes +bare 1.0 5 latest/stable canonical** base +blablaland-desktop 1.0.1 3 latest/edge adedev - +canonical-livepatch 10.10.3 316 latest/stable canonical** - +caprine 2.59.3 65 latest/stable sindresorhus - +chromium 136.0.7103.113 3137 latest/stable canonical** - +core 16-2.61.4-20241002 17210 latest/stable canonical** core +core18 20250123 2855 latest/stable canonical** base +core20 20250429 2582 latest/stable canonical** base +core22 20250408 1963 latest/stable canonical** base +core24 20250504 988 latest/stable canonical** base +cups 2.4.12-2 1100 latest/stable openprinting** - +deja-dup 46.1 624 latest/stable mterry classic +duplicity 3.0.4 524 latest/stable kenneth-loafman classic +figma-linux 0.11.4 197 latest/stable youdonthavepermissiony - +firefox 139.0-2 6227 latest/stable mozilla** - +flutter 0+git.1fa6fd6 149 latest/stable flutter-team** classic +gitkraken 11.1.1 260 latest/stable gitkraken** classic +gnome-3-26-1604 3.26.0.20221130 111 latest/stable/โ€ฆ canonical** - +gnome-3-28-1804 3.28.0-19-g98f9e67.98f9e67 198 latest/stable canonical** - +gnome-3-34-1804 0+git.3556cb3 93 latest/stable canonical** - +gnome-3-38-2004 0+git.efb213a 143 latest/stable canonical** - +gnome-42-2204 0+git.38ea591 202 latest/stable canonical** - +gnome-46-2404 0+git.d9f8bf6-sdk0+git.c8a281c 90 latest/stable canonical** - +gnome-firmware 45.0-16-g1e19cec 8 latest/stable superm1 - +gnome-system-monitor 48.1 193 latest/stable/โ€ฆ canonical** - +google-cloud-cli 524.0.0 341 latest/stable google-cloud-sdk** classic +gtk-common-themes 0.1-81-g442e511 1535 latest/stable/โ€ฆ canonical** - +hunspell-dictionaries-1-7-2004 1.7-20.04+pkg-6fd6 2 latest/stable brlin - +journey 2.14.6 23 latest/stable 2appstudio** - +mesa-2404 24.2.8 495 latest/stable canonical** - +multipass 1.15.1 14535 latest/stable canonical** - +postman 11.47.1 329 latest/beta postman-inc** - +pre-commit 2.13.0+pkg-3696 478 latest/beta brlin classic +pwdsafety v0.4.0 2 latest/stable edoardottt - +snap-store 41.3-72-g80e7130 1216 latest/stable/โ€ฆ canonical** - +snapd 2.68.4 24505 latest/stable canonical** snapd +snapd-desktop-integration 0.9 253 latest/stable/โ€ฆ canonical** - +telegram-desktop 5.14.3 6639 latest/stable telegram-desktop** - +utilso 4.4.0 34 latest/stable sleptsov -