12 Commits

Author SHA1 Message Date
41dfa6674a Merge pull request 'feat(lib): Initialize libnextcloud C++17 library scaffolding' (#26) from create-libnextcloud into develop
Reviewed-on: #26
2026-01-28 18:34:11 +00:00
2ed2177577 Merge pull request 'docs(config): Update README with JSON configuration format' (#24) from setup-build-config-system into develop
Reviewed-on: #24
2026-01-28 18:34:02 +00:00
092b823959 Merge pull request 'Add 3DS Docker Development Environment with CIA Support' (#23) from docker-for-devkitarm into develop
Reviewed-on: #23
2026-01-28 18:33:44 +00:00
3d6c8fa97b Merge pull request 'feat(config): implement configuration system and contributing guide (#6, #4)' (#22) from setup-config into develop
Reviewed-on: #22
2026-01-28 18:13:33 +00:00
bed4cc0121 feat(lib): initialize libnextcloud C++17 library scaffolding (#25) 2026-01-28 09:47:34 -08:00
e2d31dc053 Adds plan doc for creating our shared nextcloud library. 2026-01-27 09:36:44 -08:00
518826b908 docs(config): update README with JSON configuration format
Update documentation to reflect the actual JSON-based configuration
system instead of the old INI-style format.

Changes:
- Updated Quick Start section to reference config.example.json
- Rewrote Configuration section with JSON examples
- Added detailed environment variable override documentation
- Included CI/CD usage examples
- Documented all supported environment variables

All acceptance criteria from Issue #6 verified:
✓ config.example.json created and documented
✓ load-config.sh correctly parses JSON
✓ Environment variables take precedence over JSON
✓ Validation script catches missing required fields
✓ Documentation clear for new developers
✓ CI can inject credentials via env vars

Related: #6
2026-01-27 08:53:02 -08:00
014402d3cc Adds documentation of building and using our dev container. 2026-01-27 07:05:56 -08:00
815f865060 Adds scripts to work with our dev containers. 2026-01-27 06:46:28 -08:00
d1f98c92dd Adds Dockerfile for the 3ds build container. 2026-01-27 06:30:45 -08:00
51c18cd986 Adds initial plan for Docker containers to build using VitaSDK. 2026-01-27 04:13:40 -08:00
44ae8b436a Adds plans for docker containers to build for nintendo systems. 2026-01-27 03:07:46 -08:00
18 changed files with 4055 additions and 48 deletions

2
.gitignore vendored
View File

@@ -70,3 +70,5 @@ third-party/build/
*.tmp
*.bak
*.cache
test-builds

View File

@@ -0,0 +1,749 @@
# libnextcloud Shared Library Plan
**Created**: 2026-01-27
**Status**: 📋 Planning
**Target**: Cross-platform C++17 shared library for Nextcloud connectivity
**Branch**: `create-libnextcloud`
---
## Overview
Create `libnextcloud` - a cross-platform C++17 shared library that provides Nextcloud connectivity for embedded devices and homebrew platforms. The library will handle all Nextcloud communication, authentication, file operations, and settings management through a clean, platform-agnostic API.
**Design Philosophy**:
- **Platform-agnostic**: Works on 3DS, Switch, Wii U, Vita, PC, etc.
- **Minimal dependencies**: Only libcurl, mbedTLS, and tinyxml2
- **Header-only where possible**: nlohmann/json for configuration
- **Modern C++17**: Using standard library features
- **Testable**: Mock-friendly design with dependency injection
- **Documented**: Doxygen API documentation
---
## Project Structure
```
shared/
├── include/
│ └── nextcloud/
│ ├── client.hpp # Main client interface
│ ├── webdav_client.hpp # WebDAV protocol implementation
│ ├── auth.hpp # Authentication manager
│ ├── upload_manager.hpp # File upload with chunking
│ ├── folder_manager.hpp # Remote folder operations
│ ├── config.hpp # Configuration management
│ ├── types.hpp # Common types and enums
│ └── version.hpp # Library version info
├── src/
│ ├── webdav_client.cpp
│ ├── auth.cpp
│ ├── upload_manager.cpp
│ ├── folder_manager.cpp
│ └── config.cpp
├── tests/
│ ├── webdav_client_test.cpp
│ ├── auth_test.cpp
│ ├── upload_manager_test.cpp
│ ├── folder_manager_test.cpp
│ ├── config_test.cpp
│ └── mocks/
│ ├── mock_http_client.hpp
│ └── mock_xml_parser.hpp
├── examples/
│ ├── simple_upload.cpp
│ ├── folder_listing.cpp
│ └── authentication.cpp
├── docs/
│ ├── api.md # API documentation
│ ├── architecture.md # Design overview
│ └── Doxyfile # Doxygen configuration
├── CMakeLists.txt
└── README.md
```
---
## Dependencies
### Required
- **libcurl** (7.68+): HTTP/HTTPS client
- **mbedTLS** (2.16+): SSL/TLS support (works on embedded)
- **tinyxml2** (9.0+): Lightweight XML parsing
### Header-Only
- **nlohmann/json** (3.10+): JSON parsing/serialization
### Testing
- **Google Test** (1.11+): Unit testing framework
- **Google Mock** (1.11+): Mocking framework
### Build Tools
- **CMake** (3.15+): Build system
- **C++17 compiler**: GCC 7+, Clang 5+, MSVC 2017+
---
## Implementation Phases
## Phase 1: Project Scaffolding (Issue #??)
**Goal**: Set up the library project structure and build system.
### Tasks
- [ ] Create `shared/` directory structure
- [ ] Set up CMakeLists.txt with:
- Library target (static/shared)
- C++17 standard
- Include directories
- Dependency linking (curl, mbedtls, tinyxml2)
- Install rules
- Export config for downstream projects
- [ ] Create version.hpp with semantic versioning
- [ ] Create types.hpp with common enums and structures:
- `NextcloudError` enum
- `UploadProgress` struct
- `FileInfo` struct
- `FolderInfo` struct
- [ ] Set up Google Test framework
- [ ] Create basic README for the library
- [ ] Add pkg-config file generation
- [ ] Verify library compiles as standalone project
### Acceptance Criteria
- [ ] CMake builds library successfully
- [ ] Can link against library from test project
- [ ] Version info accessible at runtime
- [ ] Ready for component implementation
**Estimated Time**: 4-6 hours
**Priority**: Critical (blocks all other work)
---
## Phase 2: WebDAV Client (Issue #8)
**Goal**: Implement HTTP/WebDAV communication layer.
### Tasks
- [ ] Create `webdav_client.hpp` interface
- [ ] Implement HTTP wrapper around libcurl:
- GET, PUT, POST, DELETE, custom methods
- Request/response headers
- Request body (string, stream)
- Response body handling
- Timeout configuration
- User-Agent setting
- [ ] Add SSL/TLS support with mbedTLS
- [ ] Implement WebDAV methods:
- PROPFIND (list files/folders)
- MKCOL (create folder)
- PUT (upload file)
- DELETE (remove file/folder)
- MOVE (rename/move)
- COPY (duplicate)
- [ ] Parse WebDAV XML responses (using tinyxml2):
- Multi-status responses
- File properties (size, mtime, type)
- Error responses
- [ ] Implement error handling:
- HTTP status codes
- Network errors
- XML parsing errors
- Error code mapping
- [ ] Add timeout and retry logic
- [ ] Write unit tests with mocked HTTP
- [ ] Document API in Doxygen format
### API Design
```cpp
class WebDAVClient {
public:
WebDAVClient(const std::string& baseUrl);
// Core HTTP
Response get(const std::string& path);
Response put(const std::string& path, const std::vector<uint8_t>& data);
Response delete_(const std::string& path);
// WebDAV operations
std::vector<FileInfo> propfind(const std::string& path, int depth = 1);
bool mkcol(const std::string& path);
bool move(const std::string& from, const std::string& to);
bool copy(const std::string& from, const std::string& to);
// Configuration
void setTimeout(int seconds);
void setAuthHeader(const std::string& header);
};
```
### Acceptance Criteria
- [ ] All WebDAV methods implemented
- [ ] SSL/TLS connections working
- [ ] XML responses correctly parsed
- [ ] Error handling comprehensive
- [ ] Unit tests with >80% coverage
- [ ] API documented
- [ ] Works with test Nextcloud servers
**Estimated Time**: 12-16 hours
**Priority**: Critical (foundation for all features)
**Dependencies**: Phase 1 complete
---
## Phase 3: Authentication System (Issue #9)
**Goal**: Handle authentication with Nextcloud servers.
### Tasks
- [ ] Create `auth.hpp` interface
- [ ] Implement HTTP Basic Authentication:
- Base64 encoding
- Authorization header generation
- Credential storage
- [ ] Add authentication verification:
- Test connection to server
- Validate credentials
- Return meaningful error codes
- [ ] Secure credential handling:
- In-memory only (no disk storage by default)
- Platform-specific secure storage hooks
- [ ] Session management:
- Keep-alive connections
- Connection pooling
- Timeout handling
- [ ] Future: OAuth2 support (stubbed for now)
- [ ] Write unit tests for auth flows
- [ ] Document security considerations
### API Design
```cpp
class AuthManager {
public:
// Basic Auth
void setBasicAuth(const std::string& username, const std::string& password);
std::string getAuthHeader() const;
// Verification
bool verifyConnection(WebDAVClient& client);
// Session management
void clearCredentials();
bool hasCredentials() const;
};
```
### Acceptance Criteria
- [ ] Basic auth working with real Nextcloud
- [ ] Credentials never logged or leaked
- [ ] Connection verification works
- [ ] Error messages helpful
- [ ] Unit tests cover edge cases
- [ ] API documented
**Estimated Time**: 6-8 hours
**Priority**: High
**Dependencies**: Phase 2 complete
---
## Phase 4: Upload Manager (Issue #10)
**Goal**: Implement file upload with chunking and progress tracking.
### Tasks
- [ ] Create `upload_manager.hpp` interface
- [ ] Implement streaming upload:
- Read file in chunks
- Send via PUT requests
- Handle large files (>1GB)
- [ ] Add chunking support:
- Configurable chunk size (default: 10MB)
- Resume capability (future)
- Parallel chunks (future)
- [ ] Progress tracking:
- Callback interface
- Bytes uploaded / total
- Transfer speed
- Time remaining estimate
- [ ] Error handling and retry:
- Network failures
- Server errors (503, 507)
- Automatic retry with backoff
- Partial upload cleanup
- [ ] Path handling:
- URL encoding
- Special characters
- Nested folders
- [ ] Write unit tests with mock uploads
- [ ] Document upload best practices
### API Design
```cpp
class UploadManager {
public:
using ProgressCallback = std::function<void(const UploadProgress&)>;
UploadManager(WebDAVClient& client, AuthManager& auth);
// Upload operations
bool uploadFile(
const std::string& localPath,
const std::string& remotePath,
ProgressCallback callback = nullptr
);
// Configuration
void setChunkSize(size_t bytes);
void setRetryCount(int count);
void setTimeout(int seconds);
};
struct UploadProgress {
std::string filename;
size_t bytesUploaded;
size_t totalBytes;
float percentComplete;
float bytesPerSecond;
int secondsRemaining;
};
```
### Acceptance Criteria
- [ ] Uploads files successfully
- [ ] Chunking works for large files
- [ ] Progress callback accurate
- [ ] Handles network failures gracefully
- [ ] Retries work correctly
- [ ] Unit tests with various file sizes
- [ ] API documented
**Estimated Time**: 10-12 hours
**Priority**: High
**Dependencies**: Phases 2, 3 complete
---
## Phase 5: Folder Management (Issue #11)
**Goal**: Remote folder operations and navigation.
### Tasks
- [ ] Create `folder_manager.hpp` interface
- [ ] Implement folder listing:
- List contents of remote folder
- Parse file metadata (size, mtime, type)
- Recursive listing support
- Filtering (files only, folders only)
- [ ] Folder creation:
- Create single folder
- Create nested folders (mkdir -p)
- Validate folder names
- [ ] Folder navigation:
- Path normalization
- Parent folder detection
- Breadcrumb generation
- [ ] Caching (optional):
- Cache folder contents
- TTL-based invalidation
- Memory limits
- [ ] Write unit tests
- [ ] Document folder operations
### API Design
```cpp
class FolderManager {
public:
FolderManager(WebDAVClient& client, AuthManager& auth);
// Folder operations
std::vector<FileInfo> listFolder(const std::string& path);
bool createFolder(const std::string& path);
bool createFolders(const std::string& path); // mkdir -p
bool deleteFolder(const std::string& path);
bool folderExists(const std::string& path);
// Navigation helpers
std::string getParentFolder(const std::string& path);
std::vector<std::string> getBreadcrumbs(const std::string& path);
};
struct FileInfo {
std::string name;
std::string path;
bool isDirectory;
size_t size;
time_t modifiedTime;
std::string contentType;
};
```
### Acceptance Criteria
- [ ] Lists folders correctly
- [ ] Creates folders successfully
- [ ] Handles nested paths
- [ ] Metadata parsing accurate
- [ ] Unit tests comprehensive
- [ ] API documented
**Estimated Time**: 8-10 hours
**Priority**: Medium
**Dependencies**: Phases 2, 3 complete
---
## Phase 6: Favorites and Recent Folders (Issue #12)
**Goal**: Persistence layer for user preferences.
### Tasks
- [ ] Create `config.hpp` interface
- [ ] Implement favorites management:
- Add favorite folder
- Remove favorite folder
- List favorites
- Reorder favorites
- [ ] Implement recent folders tracking:
- Auto-track used folders
- Configurable limit (default: 5)
- LRU eviction
- Duplicate detection
- [ ] JSON persistence:
- Save to file
- Load from file
- Handle missing/corrupt files
- Migration support
- [ ] Platform-specific paths:
- Linux: ~/.config/nextcloud-share/
- 3DS: /nextcloud-share/
- Switch: /switch/nextcloud-share/
- [ ] Write unit tests
- [ ] Document config format
### API Design
```cpp
class Config {
public:
Config(const std::string& configPath = "");
// Favorites
void addFavorite(const std::string& path, const std::string& name = "");
void removeFavorite(const std::string& path);
std::vector<FolderInfo> getFavorites() const;
// Recent folders
void addRecentFolder(const std::string& path);
std::vector<std::string> getRecentFolders() const;
void setMaxRecentFolders(int count);
// Persistence
bool load();
bool save();
};
struct FolderInfo {
std::string path;
std::string displayName;
time_t lastUsed;
};
```
### Acceptance Criteria
- [ ] Favorites persist across restarts
- [ ] Recent folders tracked correctly
- [ ] JSON format clean and readable
- [ ] Handles missing config gracefully
- [ ] Unit tests cover edge cases
- [ ] API documented
**Estimated Time**: 6-8 hours
**Priority**: Low
**Dependencies**: None (standalone)
---
## Phase 7: Testing and Documentation (Issue #13)
**Goal**: Comprehensive test coverage and documentation.
### Tasks
- [ ] Achieve >80% code coverage
- [ ] Integration tests with real Nextcloud:
- Test against cloud.tomusan.com
- Test against disobedient.cloud
- Verify all operations work
- [ ] Mock server for offline testing:
- Mock HTTP responses
- Simulate errors
- Test edge cases
- [ ] Performance testing:
- Large file uploads
- Many small files
- Concurrent operations
- [ ] Generate Doxygen documentation
- [ ] Write architecture document
- [ ] Create usage examples
- [ ] Document build process
- [ ] Add API reference
### Documentation Structure
```
docs/
├── api.md # Full API reference
├── architecture.md # Library design and internals
├── building.md # Build instructions
├── examples.md # Usage examples
├── testing.md # How to run tests
├── contributing.md # Contribution guidelines
└── changelog.md # Version history
```
### Acceptance Criteria
- [ ] All classes have Doxygen comments
- [ ] Code coverage >80%
- [ ] Integration tests pass
- [ ] Documentation complete
- [ ] Examples compile and run
- [ ] Ready for platform integration
**Estimated Time**: 10-12 hours
**Priority**: High
**Dependencies**: All phases complete
---
## Issues to Create
Based on this plan, create the following Gitea issues:
### Issue: Initialize libnextcloud Project Structure
**Labels**: library, setup, priority:critical
**Description**:
```
Set up the shared library project structure and build system for libnextcloud.
## Tasks
- [ ] Create `shared/` directory structure
- [ ] Set up CMakeLists.txt for library
- [ ] Create version.hpp and types.hpp
- [ ] Set up Google Test framework
- [ ] Create basic README
- [ ] Add pkg-config file generation
- [ ] Verify library compiles standalone
## Dependencies
- libcurl 7.68+
- mbedTLS 2.16+
- tinyxml2 9.0+
- Google Test 1.11+
## Acceptance Criteria
- [ ] CMake builds library successfully
- [ ] Can link against library from test project
- [ ] Version info accessible at runtime
- [ ] Ready for component implementation
Estimated: 4-6 hours
Blocks: #8, #9, #10, #11, #12, #13
```
### Keep Existing Issues (Update Dependencies)
**Issue #8**: Design and implement WebDAV client
- Add dependency: "Requires libnextcloud scaffolding (new issue)"
- Priority: High
- Estimated: 12-16 hours
**Issue #9**: Implement authentication system
- Add dependency: "Requires #8"
- Priority: High
- Estimated: 6-8 hours
**Issue #10**: Implement file upload functionality
- Add dependency: "Requires #8, #9"
- Priority: High
- Estimated: 10-12 hours
**Issue #11**: Implement folder management
- Add dependency: "Requires #8, #9"
- Priority: Medium
- Estimated: 8-10 hours
**Issue #12**: Implement favorites and recent folders
- Priority: Low
- Estimated: 6-8 hours
**Issue #13**: Write unit tests for shared library
- Add dependency: "Requires #8-#12"
- Priority: High
- Estimated: 10-12 hours
---
## Build System Design
### CMakeLists.txt Structure
```cmake
cmake_minimum_required(VERSION 3.15)
project(libnextcloud VERSION 0.1.0 LANGUAGES CXX)
# C++17 required
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Library sources
add_library(nextcloud
src/webdav_client.cpp
src/auth.cpp
src/upload_manager.cpp
src/folder_manager.cpp
src/config.cpp
)
# Include directories
target_include_directories(nextcloud
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Dependencies
find_package(CURL REQUIRED)
find_package(MbedTLS REQUIRED)
find_package(tinyxml2 REQUIRED)
target_link_libraries(nextcloud
PUBLIC
CURL::libcurl
MbedTLS::mbedtls
tinyxml2::tinyxml2
)
# Testing
if(BUILD_TESTING)
enable_testing()
add_subdirectory(tests)
endif()
# Install rules
install(TARGETS nextcloud EXPORT nextcloudTargets)
install(DIRECTORY include/ DESTINATION include)
install(EXPORT nextcloudTargets
FILE nextcloudTargets.cmake
NAMESPACE nextcloud::
DESTINATION lib/cmake/nextcloud
)
```
### Platform-Specific Considerations
**Nintendo 3DS**:
- Static library only (no shared objects)
- mbedTLS available via dkp-pacman
- libcurl with 3DS patches
- Filesystem: `/nextcloud-share/config.json`
**Nintendo Switch**:
- Static library
- Standard libcurl and mbedTLS
- Filesystem: `/switch/nextcloud-share/config.json`
**Linux/PC**:
- Shared library (.so) or static
- System libcurl and mbedTLS
- Filesystem: `~/.config/nextcloud-share/config.json`
---
## Testing Strategy
### Unit Tests
- Mock all external dependencies (HTTP, filesystem)
- Test each class in isolation
- Cover edge cases and error conditions
- Fast execution (<1 second total)
### Integration Tests
- Real HTTP requests to test Nextcloud servers
- Require valid credentials from config.json
- Test full workflows end-to-end
- Can be skipped if credentials not available
### Performance Tests
- Upload 1GB file and measure time
- Upload 1000 small files
- Concurrent uploads
- Memory usage profiling
### Test Configuration
```json
{
"test": {
"servers": [
{
"name": "tomusan",
"url": "https://cloud.tomusan.com",
"username": "test",
"password": "xxx"
},
{
"name": "disobedient",
"url": "https://disobedient.cloud/nextcloud",
"username": "test",
"password": "xxx"
}
]
}
}
```
---
## Timeline Estimate
**Total Estimated Time**: 56-74 hours
| Phase | Tasks | Estimated Time |
|-------|-------|----------------|
| 1. Scaffolding | Project setup | 4-6 hours |
| 2. WebDAV Client | HTTP/WebDAV implementation | 12-16 hours |
| 3. Authentication | Auth system | 6-8 hours |
| 4. Upload Manager | File uploads | 10-12 hours |
| 5. Folder Management | Folder operations | 8-10 hours |
| 6. Favorites/Recent | Config persistence | 6-8 hours |
| 7. Testing/Docs | Tests and docs | 10-12 hours |
**Realistic Timeline**: 2-3 weeks working part-time (15-20 hrs/week)
---
## Success Criteria
The library is complete when:
- ✅ All phases implemented and tested
- ✅ Code coverage >80%
- ✅ Integration tests pass with real Nextcloud
- ✅ API documentation complete
- ✅ Examples compile and run
- ✅ Can be integrated into 3DS app
- ✅ Ready for additional platforms (Switch, Wii U, etc.)
---
## Next Steps
1. **Review this plan** - Adjust scope, estimates, priorities
2. **Create Gitea issues** - One for scaffolding, update existing issues
3. **Start Phase 1** - Set up project structure
4. **Implement phases sequentially** - Each phase depends on previous
5. **Test continuously** - Don't defer testing to the end
---
**Ready to proceed?** Let's create the issues and start building!

1153
.plans/DockerForDevkitARM.md Normal file

File diff suppressed because it is too large Load Diff

362
.plans/DockerForVitaSDK.md Normal file
View File

@@ -0,0 +1,362 @@
# Docker Build Environment Plan for VitaSDK (PS Vita)
**Status**: Planning / Research
**Last Updated**: 2026-01-27
---
## Overview
PS Vita homebrew development uses **VitaSDK**, a completely separate toolchain from devkitPro. This requires a different container approach but follows similar principles: extend official base images and install all available packages for a complete development environment.
**Key Differences from devkitPro**:
- Separate ecosystem with its own toolchain (vita-toolchain)
- Different package manager: `vdpm` (shell-based) instead of `dkp-pacman`
- Different build system: CMake with Vita-specific macros
- Official Docker images: `vitasdk/vitasdk` (not on devkitPro organization)
- Output formats: SELF (executable), VPK (installable package archive)
---
## PS Vita Platform Capabilities
### Hardware Features
- **Networking**: ✅ Built-in Wi-Fi (802.11 b/g/n)
- Optional 3G modem (discontinued in 2013, limited availability)
- Bluetooth 2.1+EDR
- **Screenshots**: ✅ Native system-level screenshot capability
- **Cameras**: ✅ Dual 0.3MP cameras (front and back)
- VGA resolution (640×480 @ 60fps)
- Can capture photos and videos
- **Display**: 5-inch OLED touchscreen (original) or LCD (slim)
- **CPU**: Quad-core ARM Cortex-A9 MPCore
- **GPU**: Quad-core PowerVR SGX543MP4+
- **RAM**: 512 MB system RAM, 128 MB VRAM
### Project Fit Assessment
**Networking**: Yes - Wi-Fi built-in, suitable for Nextcloud uploads
**Screenshots**: Yes - native system capability for game captures
**Cameras**: Yes - can take photos with built-in cameras
**Homebrew Scene**: Active community with VitaSDK
**Container Support**: Official Docker images available
**Priority**: **HIGH** - Meets all requirements (networking + screenshots + cameras)
---
## VitaSDK Ecosystem
### Official Resources
- **Website**: https://vitasdk.org/
- **GitHub Organization**: https://github.com/vitasdk (15 repositories)
- **Docker Repository**: https://github.com/vitasdk/docker
- **Package Repository**: https://github.com/vitasdk/packages (updated frequently)
- **Samples Repository**: https://github.com/vitasdk/samples (335 stars)
- **Documentation**: https://docs.vitasdk.org/
### Toolchain Components
- **vita-toolchain**: ARM-based cross-compiler (MIT license)
- **newlib**: PS Vita port of C library (GPL-2.0)
- **vita-headers**: System headers (233 stars, 94 forks)
- **buildscripts**: CMake-based build system (65 stars)
- **taihen**: Plugin framework
- **libvita2d**: 2D graphics library
### Package Management
- **Tool**: vdpm (Vita SDK Package Manager)
- **Type**: Shell-based installer scripts
- **Repository**: https://github.com/vitasdk/packages
- **Installation**: Bootstrap with `./install-all.sh` from vdpm repo
- **Build Format**: vita-makepkg (similar to Arch Linux makepkg)
### Build System
- **Primary**: CMake with Vita-specific macros
- `vita_create_self()` - Creates SELF executable
- `vita_create_vpk()` - Creates VPK package
- **Output Formats**:
- SELF: Signed ELF executable format
- VPK: Installable package archive (SELF + data + metadata)
---
## Official Docker Images
### Available on Docker Hub
```bash
# Search results show multiple official images
docker.io/vitasdk/vitasdk # Main official image
docker.io/vitasdk/vitasdk-softfp # Soft float variant
docker.io/vitasdk/buildscripts # Build tools base image
```
### Base Image Structure
From `github.com/vitasdk/docker`:
**Main Dockerfile**:
- Base: `vitasdk/buildscripts:latest`
- Installs: git, curl, bash, make, pkgconf, cmake, sudo
- Uses multi-stage build to clone and install vdpm
- Installs all packages via `vdpm/install-all.sh`
- Environment: `VITASDK=/usr/local/vitasdk`
**Non-root Dockerfile**:
- Same base, but creates unprivileged user
- Adds sudo access for package installation
- Better for local development (matches host UID)
---
## Container Strategy
### Approach
Unlike devkitPro platforms, VitaSDK already provides comprehensive official images with all packages pre-installed. Our strategy should be:
**Option 1: Use Official Images Directly** (Recommended)
- Use `vitasdk/vitasdk:latest` as-is
- No custom Dockerfile needed
- Pull official image when needed
- Simplest approach, maintained by VitaSDK team
**Option 2: Extend Official Images** (If customization needed)
- Base: `FROM vitasdk/vitasdk:latest`
- Add project-specific tools or scripts
- Pin to specific tag for reproducibility
- Only if we need additional packages
### Tagging Strategy
If we publish custom images:
- Format: `tomusan/vitasdk-vita:<date>` or `tomusan/vitasdk-vita:<date>-v<semver>`
- Example: `tomusan/vitasdk-vita:20251231` or `tomusan/vitasdk-vita:20251231-v1.0.0`
- Follow same conventions as devkitPro containers
---
## Package Ecosystem Research
### Known Libraries (from vdpm)
- **zlib**: Compression library
- **freetype**: Font rendering
- **libvita2d**: 2D graphics library (Vita-specific)
- **taihen**: Plugin framework (Vita-specific)
### Additional Research Needed
- [ ] Query vdpm package list for available networking libraries
- [ ] Check for curl, libcurl support
- [ ] Verify SSL/TLS libraries (mbedtls, openssl, etc.)
- [ ] Check for image format libraries (PNG, JPEG)
- [ ] Verify XML/JSON parsing libraries
- [ ] Document complete package list similar to devkitPro research
### How to Query Packages
```bash
# Run official container and list packages
podman run --rm vitasdk/vitasdk:latest bash -c "cd /usr/local/vitasdk && find . -name '*.a' -o -name '*.so'"
# Or check vdpm repository
# Clone https://github.com/vitasdk/packages and inspect package definitions
```
---
## Hardware Requirements
### Hacked Console Required
PS Vita homebrew requires modified firmware:
- **HENkaku**: Firmware 3.60
- **h-encore**: Firmware 3.65-3.68
- **Trinity**: Firmware 3.69-3.70
This is similar to 3DS requiring custom firmware (CFW). Not a blocker for development, but users need hacked consoles to run homebrew.
---
## Implementation Plan
### Phase 1: Research & Validation
- [ ] Test official `vitasdk/vitasdk` image locally
- [ ] Create simple "Hello World" program
- [ ] Build VPK package and test on hardware/emulator
- [ ] Document build process
- [ ] Query complete package list from vdpm
- [ ] Verify networking library availability (curl, SSL/TLS)
### Phase 2: Integration Planning
- [ ] Determine if custom Dockerfile is needed (likely not)
- [ ] Create build scripts for Vita platform
- `scripts/build-vita.sh` - Build project using container
- `scripts/container-shell-vita.sh` - Interactive development shell
- [ ] Update main `scripts/build-container.sh` to handle VitaSDK
- [ ] Document Vita-specific build flags and configuration
### Phase 3: Project Integration
- [ ] Create Vita source directory structure
- [ ] Implement Nextcloud client for Vita
- [ ] Test screenshot upload functionality
- [ ] Test camera photo upload functionality
- [ ] Integrate with main project build system
---
## Platform Priority Assessment
**Priority: HIGH**
Justification:
- ✅ Full networking support (Wi-Fi built-in)
- ✅ Native screenshot capability for game captures
- ✅ Dual cameras for photo capture
- ✅ Active homebrew community and toolchain
- ✅ Official Docker images available
- ✅ Similar form factor to 3DS (handheld gaming device)
- ✅ Fits project goals perfectly
**Recommendation**: Add PS Vita alongside 3DS, Switch, and Wii U as HIGH priority platform.
---
## Differences from devkitPro Platforms
| Aspect | devkitPro | VitaSDK |
|--------|-----------|---------|
| **Organization** | devkitPro | vita-dev (separate) |
| **Toolchain** | devkitARM/A64/PPC | vita-toolchain (ARM) |
| **Package Manager** | dkp-pacman (Arch-style) | vdpm (shell scripts) |
| **Build System** | Native makefiles + CMake | CMake with Vita macros |
| **Docker Hub** | devkitpro/* | vitasdk/* |
| **Package Format** | .pkg.tar.xz | vita-makepkg scripts |
| **Output Format** | .elf, .nro, .rpx | .self, .vpk |
| **Install Path** | /opt/devkitpro | /usr/local/vitasdk |
---
## Container Usage Examples
### Using Official Image Directly
```bash
# Pull official image
podman pull vitasdk/vitasdk:latest
# Build project
podman run --rm -v .:/project:z -w /project/vita \
vitasdk/vitasdk:latest \
cmake -B build && cmake --build build
# Interactive shell for development
podman run --rm -it -v .:/project:z -w /project \
vitasdk/vitasdk:latest \
bash
```
### If Custom Image Needed
```dockerfile
# vita.Dockerfile
FROM vitasdk/vitasdk:latest
# Add any project-specific tools
RUN apk add --no-cache \
vim \
tree \
htop
# Set working directory
WORKDIR /project
```
---
## Community & Support
### Official Channels
- **Discord**: Active VitaSDK community server
- **Matrix**: Bridge to Discord
- **IRC**: #vitasdk on libera.chat
- **Forums**: Various homebrew forums
### Related Projects
- **VitaShell**: File manager (reference for file operations)
- **Adrenaline**: PSP emulator (advanced homebrew example)
- **RetroArch**: Multi-emulator (networking reference)
- Various homebrew games and apps using VitaSDK
---
## Hardware Specifications
| Component | Specification |
|-----------|---------------|
| **CPU** | Quad-core ARM Cortex-A9 MPCore |
| **GPU** | Quad-core PowerVR SGX543MP4+ |
| **RAM** | 512 MB + 128 MB VRAM |
| **Display** | 5" OLED/LCD touchscreen, 960×544 (qHD) |
| **Storage** | Proprietary memory cards (4-64 GB) |
| **Cameras** | Front/back 0.3MP (VGA @ 60fps) |
| **Connectivity** | Wi-Fi b/g/n, Bluetooth 2.1+EDR, (3G optional) |
| **Battery** | 2210 mAh (3-5 hours gameplay) |
| **Input** | Touchscreen, rear touchpad, dual analog sticks, buttons, Sixaxis motion |
---
## References
### Official Documentation
- [VitaSDK Website](https://vitasdk.org/) - Main landing page
- [VitaSDK GitHub](https://github.com/vitasdk) - Organization with all repos
- [VitaSDK Docker](https://github.com/vitasdk/docker) - Official Dockerfile source
- [VitaSDK Packages](https://github.com/vitasdk/packages) - Available libraries
- [VitaSDK Samples](https://github.com/vitasdk/samples) - Example code
- [VitaSDK Documentation](https://docs.vitasdk.org/) - API reference
### Docker Images
- [Docker Hub - vitasdk/vitasdk](https://hub.docker.com/r/vitasdk/vitasdk)
- [Docker Hub - vitasdk/buildscripts](https://hub.docker.com/r/vitasdk/buildscripts)
### Hardware Information
- [PlayStation Vita - Wikipedia](https://en.wikipedia.org/wiki/PlayStation_Vita) - Comprehensive hardware specs
- [PS Vita Dev Wiki](https://wiki.henkaku.xyz/) - Homebrew development wiki
### Community Resources
- VitaSDK Discord Server - Active developer community
- [/r/vitahacks](https://reddit.com/r/vitahacks) - Reddit community
---
## Next Steps
When ready to implement PS Vita support:
1. **Test Official Image**:
```bash
podman pull vitasdk/vitasdk:latest
podman run --rm -it vitasdk/vitasdk:latest bash
```
2. **Create Hello World**:
- Simple CMakeLists.txt
- Basic main.c with vita2d graphics
- Build VPK package
3. **Research Networking Libraries**:
- Query vdpm for available packages
- Test curl/libcurl availability
- Verify SSL/TLS support
4. **Determine Custom Dockerfile Need**:
- If official image has everything → use directly
- If missing tools → create custom Dockerfile extending official image
5. **Update Main Plan**:
- Add PS Vita to DockerForDevkitARM.md platform summary
- Note it uses separate VitaSDK ecosystem
- Include in Phase 3 implementation alongside Wii U
---
## Notes
- VitaSDK is completely independent from devkitPro - different organization, different toolchain
- Official images already include most/all packages via vdpm install-all
- May not need custom Dockerfile at all - official image might be sufficient
- PS Vita was discontinued in 2019, but homebrew scene remains active
- Estimated 15-16 million units sold worldwide (smaller than 3DS but larger than Wii U)
- Active indie game development continues as of 2026

186
README.md
View File

@@ -62,87 +62,177 @@ git clone https://git.tomusan.com/your-username/nextcloud-share.git
cd nextcloud-share
```
### 2. Configure Test Environment
### 2. Build the 3DS Development Container
Copy the example configuration file:
Build the container image (first time only, or when Dockerfile changes):
```bash
cp config.example config
./scripts/build-container.sh 3ds
```
Edit `config` and add your test Nextcloud credentials:
This creates a complete 3DS development environment with:
- devkitARM GCC 15.2.0
- All 47 available 3DS portlibs
- CIA creation tools (bannertool, makerom, ctrtool)
- Build time: ~10-15 minutes on first build
```ini
# Local test configuration - DO NOT COMMIT THIS FILE
NEXTCLOUD_URL=https://your-nextcloud-instance.com
NEXTCLOUD_USER=your-username
NEXTCLOUD_PASSWORD=your-password
```
**Note**: The container is built once and reused. You only rebuild when the Dockerfile changes.
**Note**: The `config` file is in `.gitignore` and will never be committed. Each developer should create their own local config.
### 3. Build Using Podman
#### Build the 3DS version:
### 3. Compile Your 3DS Project
```bash
# Build the container image (first time only)
podman build -f docker/devkitarm.Dockerfile -t nextcloud-share-3ds .
# From within your project directory
cd your-3ds-project
podman run --rm -v .:/project:z tomusan/devkitarm-3ds:latest make
# Compile the project
podman run --rm -v ./:/project:z nextcloud-share-3ds make -C 3ds
# Output files will be in 3ds/build/
# Or specify a path
podman run --rm -v ~/my-game:/project:z tomusan/devkitarm-3ds:latest make
```
#### Run tests:
**Output files**: `.3dsx` (homebrew), `.elf` (debug), `.smdh` (metadata), `.cia` (installable)
### 4. Interactive Development Shell
For debugging or manual builds:
```bash
podman run --rm -v ./:/project:z nextcloud-share-3ds make test
# Current directory
./scripts/container-shell.sh
# Specific project
./scripts/container-shell.sh ~/my-3ds-game
# With extra volumes or environment
./scripts/container-shell.sh ~/my-game -v /data:/data:z -e DEBUG=1
```
#### Interactive development shell:
Inside the container, all devkitARM tools are available in PATH. Run `make` to build, `exit` to leave.
### 5. Configure Test Environment (Optional)
For testing with real Nextcloud servers, copy the example configuration:
```bash
podman run --rm -it -v ./:/project:z nextcloud-share-3ds bash
cp config.example.json config.json
```
Edit `config.json` and add your test Nextcloud credentials:
```json
{
"nextcloud": {
"url": "https://your-nextcloud-instance.com",
"username": "your-username",
"password": "your-app-password"
},
"settings": {
"maxRecentFolders": 5,
"uploadChunkSize": 10485760
}
}
```
**Note**: The `config.json` file is in `.gitignore` and will never be committed.
## 🔧 Building
Detailed build instructions for each platform will be added as they are implemented. See platform-specific README files:
### Using Development Containers
- [3ds/README.md](3ds/README.md) - Nintendo 3DS build instructions
- More coming soon...
All builds run in isolated containers with complete toolchains. See [docker/README.md](docker/README.md) for detailed container documentation.
**Available containers:**
- **3DS**: `tomusan/devkitarm-3ds:latest` - Nintendo 3DS with full CIA support
**Quick build commands:**
```bash
# Build 3DS container (first time)
./scripts/build-container.sh 3ds
# Compile a 3DS project
podman run --rm -v ~/my-game:/project:z tomusan/devkitarm-3ds:latest make
# Interactive shell
./scripts/container-shell.sh ~/my-game
```
**Build performance:**
- First build: ~10-15 minutes (downloads and compiles tools)
- Subsequent builds: Instant (uses build cache)
- Container rebuilds: Only needed when Dockerfile changes
Platform-specific build instructions:
- [docker/README.md](docker/README.md) - Container usage and CIA creation
- More platforms coming soon...
## ⚙️ Configuration
### Local Development Configuration
The `config` file (copied from `config.example`) is used for local testing:
The project uses a JSON configuration file for managing test credentials and build options.
```ini
NEXTCLOUD_URL=https://cloud.example.com
NEXTCLOUD_USER=testuser
NEXTCLOUD_PASSWORD=testpass
MAX_RECENT_FOLDERS=5 # Build-time option
**Setup:**
```bash
# Copy the example configuration
cp config.example.json config.json
# Edit config.json with your credentials
nano config.json
```
### CI/CD Environment Variables
For CI/CD pipelines, use environment variables to override the local config:
- `NEXTCLOUD_TEST_URL` - Test server URL
- `NEXTCLOUD_TEST_USER` - Test username
- `NEXTCLOUD_TEST_PASSWORD` - Test password
- `MAX_RECENT_FOLDERS` - Number of recent folders to track
Example:
**Configuration structure:**
```json
{
"nextcloud": {
"url": "https://cloud.example.com",
"username": "testuser",
"password": "your-app-password"
},
"settings": {
"maxRecentFolders": 5,
"uploadChunkSize": 10485760
}
}
```
**Loading configuration:**
```bash
NEXTCLOUD_TEST_URL=https://cloud.tomusan.com \
NEXTCLOUD_TEST_USER=ci-user \
NEXTCLOUD_TEST_PASSWORD=ci-pass \
podman run --rm -v ./:/project:z nextcloud-share-3ds make
# Load configuration and export as environment variables
source scripts/load-config.sh
# Validate configuration
./scripts/validate-config.sh
```
### Environment Variable Overrides
Environment variables take precedence over JSON configuration values. This is useful for CI/CD pipelines where you don't want to store credentials in files.
**Supported environment variables:**
- `NEXTCLOUD_URL` - Nextcloud server URL (required)
- `NEXTCLOUD_USER` - Username for authentication (required)
- `NEXTCLOUD_PASSWORD` - Password or app password (required)
- `MAX_RECENT_FOLDERS` - Number of recent folders to track (default: 5)
- `UPLOAD_CHUNK_SIZE` - Upload chunk size in bytes (default: 10485760)
- `CONFIG_FILE` - Path to config file (default: config.json)
**CI/CD Example:**
```bash
# Override configuration with environment variables
export NEXTCLOUD_URL=https://cloud.tomusan.com
export NEXTCLOUD_USER=ci-user
export NEXTCLOUD_PASSWORD=ci-pass
# Load any remaining config from file
source scripts/load-config.sh
# Run tests
podman run --rm \
-e NEXTCLOUD_URL \
-e NEXTCLOUD_USER \
-e NEXTCLOUD_PASSWORD \
-v ./:/project:z \
tomusan/devkitarm-3ds:latest \
make test
```
## 🧪 Testing

62
docker/.dockerignore Normal file
View File

@@ -0,0 +1,62 @@
# Docker build context exclusions
# Keep build context minimal for faster builds
# Git
.git/
.gitignore
.gitattributes
# Build artifacts
*.o
*.elf
*.3dsx
*.cia
*.smdh
*.nro
*.nso
*.rpx
*.rpl
*.dol
*.wad
*.vpk
*.self
build/
dist/
*.log
# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Documentation and plans (not needed in container)
docs/
.plans/
*.md
!docker/*.md
# Config files (copied separately if needed)
*.json
*.toml
*.yaml
*.yml
!package.json
# Node modules and dependencies
node_modules/
venv/
__pycache__/
*.pyc
# Cache directories
.cache/
.ccache/
*.cache
# Temporary files
tmp/
temp/
*.tmp

122
docker/3ds.Dockerfile Normal file
View File

@@ -0,0 +1,122 @@
# Nintendo 3DS Development Container
# Based on official devkitPro devkitARM image
# Contains ALL available 3DS portlibs for complete development environment
FROM devkitpro/devkitarm:20251231
LABEL maintainer="nextcloud-share contributors"
LABEL description="Complete Nintendo 3DS development environment with all available portlibs"
LABEL org.opencontainers.image.base.name="devkitpro/devkitarm:20251231"
LABEL org.opencontainers.image.title="Nintendo 3DS Development Container"
LABEL platform="3ds"
LABEL toolchain="devkitARM"
# Update package database
RUN dkp-pacman -Sy --noconfirm
# Install 3DS development group (includes devkitARM, libctru, citro3d, citro2d, tools)
RUN dkp-pacman -S --needed --noconfirm 3ds-dev
# Install ALL available 3DS portlibs (alphabetical for clarity)
# List verified from devkitpro/devkitarm:20251231 on 2026-01-27
RUN dkp-pacman -S --needed --noconfirm \
3ds-box2d \
3ds-bulletphysics \
3ds-bzip2 \
3ds-curl \
3ds-flac \
3ds-flite \
3ds-freetype \
3ds-giflib \
3ds-jansson \
3ds-libarchive \
3ds-libconfig \
3ds-libfribidi \
3ds-libiconv \
3ds-libid3tag \
3ds-libjpeg-turbo \
3ds-libjson-c \
3ds-liblua51 \
3ds-liblzma \
3ds-libmad \
3ds-libmodplug \
3ds-libogg \
3ds-libopus \
3ds-libpng \
3ds-libsidplay \
3ds-libtheora \
3ds-libvorbisidec \
3ds-libxmp \
3ds-libzstd \
3ds-lz4 \
3ds-mbedtls \
3ds-mikmod \
3ds-mpg123 \
3ds-opusfile \
3ds-physfs \
3ds-sdl \
3ds-sdl_gfx \
3ds-sdl_image \
3ds-sdl_mixer \
3ds-sdl_ttf \
3ds-tinyxml2 \
3ds-wildmidi \
3ds-wslay \
3ds-yaml_cpp \
3ds-zlib && \
dkp-pacman -Scc --noconfirm
# Install system build tools for development
# Note: devkitarm-cmake is already installed as part of 3ds-dev group
RUN apt-get update && apt-get install -y --no-install-recommends \
ccache \
ninja-build \
python3 \
python3-pip \
curl \
wget \
jq \
git \
zip \
unzip && \
rm -rf /var/lib/apt/lists/*
# Configure ccache for faster rebuilds
ENV CCACHE_DIR=/project/.ccache
ENV CCACHE_MAXSIZE=2G
# Add devkitARM compiler to PATH
ENV PATH="${DEVKITARM}/bin:/usr/lib/ccache:${PATH}"
# Build and install bannertool for CIA file creation
RUN git clone --recursive https://github.com/diasurgical/bannertool.git /tmp/bannertool && \
cd /tmp/bannertool && \
make && \
cp output/linux-x86_64/bannertool /opt/devkitpro/tools/bin/ && \
chmod +x /opt/devkitpro/tools/bin/bannertool && \
cd / && \
rm -rf /tmp/bannertool
# Build and install makerom and ctrtool for CIA file creation
RUN git clone https://github.com/3DSGuy/Project_CTR.git /tmp/Project_CTR && \
cd /tmp/Project_CTR/makerom && \
make deps && make && \
cp bin/makerom /opt/devkitpro/tools/bin/ && \
chmod +x /opt/devkitpro/tools/bin/makerom && \
cd /tmp/Project_CTR/ctrtool && \
make deps && make && \
cp bin/ctrtool /opt/devkitpro/tools/bin/ && \
chmod +x /opt/devkitpro/tools/bin/ctrtool && \
cd / && \
rm -rf /tmp/Project_CTR
# Set working directory
WORKDIR /project
# Verify installation
RUN arm-none-eabi-gcc --version && \
make --version && \
cmake --version
# Show installed 3DS packages on container startup
CMD ["bash", "-c", "echo 'Nintendo 3DS Development Container Ready' && echo 'devkitARM:' && arm-none-eabi-gcc --version | head -n1 && echo '' && echo '3DS packages installed:' && dkp-pacman -Qq | grep '^3ds-' | wc -l && echo 'packages' && bash"]

316
docker/README.md Normal file
View File

@@ -0,0 +1,316 @@
# Nintendo 3DS Development Container
Complete Docker/Podman container for Nintendo 3DS homebrew development with full CIA file creation support.
## Features
- **Complete devkitARM toolchain** - GCC 15.2.0 for ARM development
- **All 47 3DS portlibs** - Every available library including graphics, audio, networking, physics, and compression
- **CIA Creation Tools**:
- `bannertool` - Creates banner and icon files for CIA packages
- `makerom` - Assembles final CIA installation files
- `ctrtool` - Inspects and validates CIA structure
- `3dstools` - Includes 3dsxtool, smdhtool, mkromfs3ds
- **Build optimization** - ccache for faster rebuilds
- **Modern build tools** - CMake, Ninja, Python 3
## Quick Start
### Using Helper Scripts (Recommended)
The easiest way to use these containers is with the provided helper scripts:
**1. Build the container:**
```bash
./scripts/build-container.sh 3ds
```
**2. Open interactive shell:**
```bash
# Current directory
./scripts/container-shell.sh
# Specific project
./scripts/container-shell.sh ~/my-3ds-game
# With additional volumes or environment
./scripts/container-shell.sh ~/my-game -v /data:/data:z -e DEBUG=1
```
### Manual Container Usage
If you prefer to use podman/docker commands directly:
**Building the Container:**
```bash
# Using Podman (recommended for rootless operation)
podman build -t tomusan/devkitarm-3ds:latest -f docker/3ds.Dockerfile .
# Using Docker
docker build -t tomusan/devkitarm-3ds:latest -f docker/3ds.Dockerfile .
```
Build time: ~10-15 minutes on first build (downloads and compiles bannertool, makerom, ctrtool)
**Compiling a 3DS Project:**
Basic compilation (produces .3dsx homebrew file):
```bash
podman run --rm -v ./your-project:/project:z tomusan/devkitarm-3ds:latest make
```
With CIA file creation:
```bash
# Most 3DS projects with proper Makefile configuration
podman run --rm -v ./your-project:/project:z tomusan/devkitarm-3ds:latest make
```
Clean and rebuild:
```bash
podman run --rm -v ./your-project:/project:z tomusan/devkitarm-3ds:latest bash -c "make clean && make"
```
**Interactive Shell:**
For debugging or manual builds:
```bash
podman run -it --rm -v ./your-project:/project:z tomusan/devkitarm-3ds:latest bash
```
## Helper Scripts
### build-container.sh
Builds and tags development containers with automatic runtime detection (podman/docker).
**Usage:**
```bash
./scripts/build-container.sh <platform> [version]
```
**Examples:**
```bash
# Build with default version (0.1.0)
./scripts/build-container.sh 3ds
# Build with custom version
./scripts/build-container.sh 3ds 0.2.0
# Show help
./scripts/build-container.sh --help
```
**Features:**
- Auto-detects podman/docker runtime
- Validates semantic versioning (X.Y.Z format)
- Tags both version and latest
- Colored output with build status
- Shows usage examples after successful build
**Environment Variables:**
- `CONTAINER_RUNTIME` - Override runtime (podman or docker)
### container-shell.sh
Opens an interactive bash shell in the development container with your project mounted.
**Usage:**
```bash
./scripts/container-shell.sh [project-path] [podman-args...]
```
**Examples:**
```bash
# Shell in current directory
./scripts/container-shell.sh
# Shell in specific project
./scripts/container-shell.sh ~/my-3ds-game
# With additional volume mount
./scripts/container-shell.sh ~/my-game -v /data:/data:z
# With environment variable
./scripts/container-shell.sh ~/my-game -e DEBUG=1
# Multiple extra arguments
./scripts/container-shell.sh ~/my-game -v /data:/data:z -e DEBUG=1 --network=host
```
**Features:**
- First argument = project path (defaults to current directory)
- All additional arguments passed to podman/docker run
- Auto-detects podman/docker runtime
- Colored output with container information
- Project mounted at `/project` with working directory set
**Environment Variables:**
- `CONTAINER_RUNTIME` - Override runtime (podman or docker)
## Output Files
A complete 3DS build produces:
- **`.3dsx`** - Homebrew Launcher executable format
- **`.elf`** - Executable with debug symbols
- **`.smdh`** - Icon and metadata for Homebrew Launcher
- **`banner.bnr`** - Banner displayed when CIA is selected on home menu
- **`icon.icn`** - Icon file for CIA package
- **`.cia`** - Installable file for 3DS home menu
## CIA File Creation
The container includes all tools needed for complete CIA file creation:
### Manual CIA Creation Workflow
If your Makefile doesn't include CIA generation:
```bash
podman run --rm -v ./your-project:/project:z tomusan/devkitarm-3ds:latest bash -c '
# Build the application
make
# Create banner (requires banner.png and audio.wav in assets/)
bannertool makebanner -i assets/banner.png -a assets/audio.wav -o build/banner.bnr
# Create icon (requires icon.png in assets/)
bannertool makesmdh -s "App Title" -l "Description" -p "Author" \
-i assets/icon.png -o build/icon.icn
# Create CIA file (requires app.rsf in assets/)
makerom -f cia -o output.cia -target t -exefslogo \
-elf output.elf -rsf assets/app.rsf \
-banner build/banner.bnr -icon build/icon.icn \
-DAPP_TITLE="App Title" \
-DAPP_PRODUCT_CODE="CTR-P-XXXX" \
-DAPP_UNIQUE_ID="0x12345"
'
```
### Validating CIA Files
```bash
# Inspect CIA structure
podman run --rm -v ./your-project:/project:z tomusan/devkitarm-3ds:latest \
ctrtool -i output.cia
```
## Installed Libraries
The container includes all available 3DS portlibs:
**Graphics & UI:**
- citro3d, citro2d - 3DS GPU libraries
- SDL, SDL_gfx, SDL_image, SDL_mixer, SDL_ttf
- freetype, libpng, libjpeg-turbo, giflib
**Audio:**
- libopus, opusfile, libvorbisidec, libogg
- flac, libmad, libmodplug, libxmp, mikmod, mpg123
- wildmidi, libid3tag
**Networking:**
- curl, mbedtls, wslay
**Data Formats:**
- json-c, jansson, yaml_cpp, tinyxml2
- libarchive, bzip2, liblzma, lz4, libzstd, zlib
**Physics & Math:**
- box2d, bulletphysics
**Other:**
- libconfig, libfribidi, libiconv, liblua51
- physfs, libsidplay, libtheora
## Container Environment
```bash
DEVKITPRO=/opt/devkitpro
DEVKITARM=/opt/devkitpro/devkitARM
PATH includes:
- ${DEVKITARM}/bin (ARM toolchain)
- /opt/devkitpro/tools/bin (bannertool, makerom, ctrtool)
- /usr/lib/ccache (build cache)
```
## Testing
Verified working with:
- **60/61 official 3ds-examples** - 98.4% success rate
- **Checkpoint** - Real-world save manager application with full CIA creation
## Troubleshooting
### Permission Issues with Podman
The `:z` flag in volume mounts sets proper SELinux context:
```bash
-v ./project:/project:z
```
### Container Size
Expected size: ~1.6 GB (includes all libraries and build tools)
### Build Cache
To speed up rebuilds, the container uses ccache. The cache is stored in your project at `.ccache/`:
```bash
# Clean cache if needed
rm -rf ./your-project/.ccache
```
### Common Errors
**"makerom: command not found"**
- Rebuild container with latest Dockerfile (includes makerom build steps)
**"bannertool: command not found"**
- Rebuild container with latest Dockerfile (includes bannertool build steps)
**CIA creation fails silently**
- Check that all required files exist:
- `assets/app.rsf` - CIA metadata
- `assets/banner.png` and `assets/audio.wav` - Banner resources
- `assets/icon.png` - Icon resource
- `output.elf` - Compiled application
## Version Information
- **Base Image**: devkitpro/devkitarm:20251231
- **devkitARM**: GCC 15.2.0
- **CMake**: 3.31.6
- **GNU Make**: 4.3
- **3DS Packages**: 47 portlibs installed
## Building from Source
The Dockerfile includes build steps for:
1. **bannertool** (diasurgical/bannertool)
- Cloned with `--recursive` for submodules
- Built with system make
- Installed to `/opt/devkitpro/tools/bin/`
2. **makerom & ctrtool** (3DSGuy/Project_CTR)
- Cloned from active fork
- Built dependencies first with `make deps`
- Built tools with `make`
- Installed to `/opt/devkitpro/tools/bin/`
## Additional Resources
- [devkitPro Documentation](https://devkitpro.org/)
- [3DS Homebrew Development](https://www.3dbrew.org/wiki/Homebrew_Development)
- [Checkpoint Repository](https://github.com/BernardoGiordano/Checkpoint) - Example of complete CIA project
- [3ds-examples](https://github.com/devkitPro/3ds-examples) - Official examples
## License
This container configuration is provided as-is. Individual tools and libraries maintain their respective licenses:
- devkitARM: GPL/proprietary tools
- bannertool: Custom license
- makerom/ctrtool: Custom license
- Portlibs: Various open source licenses

177
scripts/build-container.sh Executable file
View File

@@ -0,0 +1,177 @@
#!/bin/bash
# Build development containers for various platforms
# Usage: ./scripts/build-container.sh <platform> [version]
#
# Platforms: 3ds, switch, wiiu, wii, gamecube, nds, gba
# Version: Semantic version (default: 0.1.0)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print colored message
print_msg() {
local color=$1
shift
echo -e "${color}$*${NC}"
}
# Print usage
usage() {
cat << EOF
Usage: $0 <platform> [version]
Build development container for specified platform.
Platforms:
3ds Nintendo 3DS (devkitARM)
switch Nintendo Switch (devkitA64) - Not yet implemented
wiiu Nintendo Wii U (devkitPPC) - Not yet implemented
wii Nintendo Wii (devkitPPC) - Not yet implemented
gamecube Nintendo GameCube (devkitPPC) - Not yet implemented
nds Nintendo DS (devkitARM) - Not yet implemented
gba Game Boy Advance (devkitARM) - Not yet implemented
Version:
Semantic version tag (default: 0.1.0)
Example: 0.1.0, 1.0.0, 0.2.0-beta
Examples:
$0 3ds # Build 3DS container with version 0.1.0
$0 3ds 0.2.0 # Build 3DS container with version 0.2.0
$0 switch # Build Switch container (when implemented)
Environment Variables:
CONTAINER_RUNTIME Container runtime to use (podman or docker, default: auto-detect)
EOF
exit 1
}
# Detect container runtime
detect_runtime() {
if [ -n "$CONTAINER_RUNTIME" ]; then
echo "$CONTAINER_RUNTIME"
return
fi
if command -v podman &> /dev/null; then
echo "podman"
elif command -v docker &> /dev/null; then
echo "docker"
else
print_msg "$RED" "Error: Neither podman nor docker found in PATH"
print_msg "$YELLOW" "Please install podman (recommended) or docker"
exit 1
fi
}
# Build container
build_container() {
local platform=$1
local version=$2
local dockerfile="docker/${platform}.Dockerfile"
local image_name="tomusan/devkitarm-${platform}"
if [ ! -f "$PROJECT_ROOT/$dockerfile" ]; then
print_msg "$RED" "Error: Dockerfile not found: $dockerfile"
print_msg "$YELLOW" "This platform may not be implemented yet."
exit 1
fi
local runtime
runtime=$(detect_runtime)
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_msg "$GREEN" "Building ${platform} container"
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo
print_msg "$YELLOW" "Platform: $platform"
print_msg "$YELLOW" "Version: $version"
print_msg "$YELLOW" "Runtime: $runtime"
print_msg "$YELLOW" "Dockerfile: $dockerfile"
print_msg "$YELLOW" "Image: ${image_name}:${version}"
print_msg "$YELLOW" " ${image_name}:latest"
echo
cd "$PROJECT_ROOT"
# Build with both version and latest tags
print_msg "$GREEN" "Starting build..."
echo
"$runtime" build \
-t "${image_name}:${version}" \
-t "${image_name}:latest" \
-f "$dockerfile" \
.
local exit_code=$?
if [ $exit_code -eq 0 ]; then
echo
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_msg "$GREEN" "✓ Build successful!"
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo
print_msg "$GREEN" "Tagged images:"
print_msg "$YELLOW" " ${image_name}:${version}"
print_msg "$YELLOW" " ${image_name}:latest"
echo
print_msg "$GREEN" "To use this container:"
print_msg "$YELLOW" " $runtime run --rm -v ./your-project:/project:z ${image_name}:latest make"
echo
print_msg "$GREEN" "For interactive shell:"
print_msg "$YELLOW" " $runtime run -it --rm -v ./your-project:/project:z ${image_name}:latest bash"
echo
else
echo
print_msg "$RED" "✗ Build failed with exit code $exit_code"
exit $exit_code
fi
}
# Main
main() {
if [ $# -lt 1 ]; then
usage
fi
local platform=$1
local version=${2:-0.1.0}
# Validate platform
case "$platform" in
3ds)
;;
switch|wiiu|wii|gamecube|nds|gba)
print_msg "$RED" "Error: Platform '$platform' is not yet implemented"
print_msg "$YELLOW" "Currently only '3ds' is available"
exit 1
;;
*)
print_msg "$RED" "Error: Unknown platform '$platform'"
echo
usage
;;
esac
# Validate version format (basic semantic versioning)
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
print_msg "$RED" "Error: Invalid version format '$version'"
print_msg "$YELLOW" "Expected format: X.Y.Z or X.Y.Z-label (e.g., 0.1.0, 1.0.0, 0.2.0-beta)"
exit 1
fi
build_container "$platform" "$version"
}
main "$@"

136
scripts/container-shell.sh Executable file
View File

@@ -0,0 +1,136 @@
#!/bin/bash
# Open interactive shell in 3DS development container
# Usage: ./scripts/container-shell.sh [project-path] [podman-args...]
#
# All arguments after project-path are passed to podman/docker run before the container name
# This allows mounting additional volumes, setting environment variables, etc.
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print colored message
print_msg() {
local color=$1
shift
echo -e "${color}$*${NC}"
}
# Print usage
usage() {
cat << 'EOF'
Usage: ./scripts/container-shell.sh [project-path] [podman-args...]
Open interactive bash shell in 3DS development container with project mounted.
Arguments:
project-path Path to project directory (default: current directory)
podman-args Additional arguments passed to podman/docker run
Examples:
# Shell in current directory
./scripts/container-shell.sh
# Shell in specific project
./scripts/container-shell.sh ~/my-3ds-game
# With additional volume mount
./scripts/container-shell.sh ~/my-game -v /data:/data:z
# With environment variable
./scripts/container-shell.sh ~/my-game -e DEBUG=1
# Multiple extra arguments
./scripts/container-shell.sh ~/my-game -v /data:/data:z -e DEBUG=1 --network=host
Inside the container:
- Project is mounted at /project
- Working directory is /project
- All devkitARM tools are in PATH
- Run 'make' to build your project
- Run 'exit' or Ctrl+D to leave
Environment Variables:
CONTAINER_RUNTIME Container runtime to use (podman or docker, default: auto-detect)
EOF
exit 1
}
# Detect container runtime
detect_runtime() {
if [ -n "$CONTAINER_RUNTIME" ]; then
echo "$CONTAINER_RUNTIME"
return
fi
if command -v podman &> /dev/null; then
echo "podman"
elif command -v docker &> /dev/null; then
echo "docker"
else
print_msg "$RED" "Error: Neither podman nor docker found in PATH"
print_msg "$YELLOW" "Please install podman (recommended) or docker"
exit 1
fi
}
# Main
main() {
# Show help
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
usage
fi
# Determine project path
local project_path="${1:-.}"
shift || true # Remove first arg if present, don't fail if no args
# Resolve absolute path
project_path=$(cd "$project_path" 2>/dev/null && pwd) || {
print_msg "$RED" "Error: Project path does not exist: ${1:-.}"
exit 1
}
# Collect remaining arguments for podman/docker run
local extra_args=("$@")
local runtime
runtime=$(detect_runtime)
local image_name="tomusan/devkitarm-3ds:latest"
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_msg "$GREEN" "3DS Development Container Shell"
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo
print_msg "$YELLOW" "Project: $project_path"
print_msg "$YELLOW" "Runtime: $runtime"
print_msg "$YELLOW" "Image: $image_name"
if [ ${#extra_args[@]} -gt 0 ]; then
print_msg "$YELLOW" "Extra: ${extra_args[*]}"
fi
echo
print_msg "$GREEN" "Type 'exit' or press Ctrl+D to leave the container"
echo
print_msg "$BLUE" "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo
# Run container with interactive shell
# Project mounted to /project, any extra args passed to podman/docker run
"$runtime" run -it --rm \
-v "$project_path:/project:z" \
"${extra_args[@]}" \
"$image_name" \
bash
}
main "$@"

131
shared/CMakeLists.txt Normal file
View File

@@ -0,0 +1,131 @@
cmake_minimum_required(VERSION 3.15)
project(libnextcloud VERSION 0.1.0 LANGUAGES CXX)
# C++17 required
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Options
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(BUILD_TESTING "Build tests" ON)
option(BUILD_EXAMPLES "Build examples" OFF)
# Library sources (currently empty, will be populated as we implement components)
set(NEXTCLOUD_SOURCES
# src/webdav_client.cpp # Will be added in future
# src/auth.cpp # Will be added in future
# src/upload_manager.cpp # Will be added in future
# src/folder_manager.cpp # Will be added in future
# src/config.cpp # Will be added in future
)
# Create library target
# For now, it's header-only (version.hpp and types.hpp)
# We'll add sources when we implement components
add_library(nextcloud INTERFACE)
# Include directories
target_include_directories(nextcloud
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# Require C++17 for consumers
target_compile_features(nextcloud INTERFACE cxx_std_17)
# Dependencies (will be uncommented as we add implementation)
# find_package(CURL REQUIRED)
# find_package(MbedTLS REQUIRED)
# find_package(tinyxml2 REQUIRED)
# Link libraries (commented out until we have actual implementation)
# target_link_libraries(nextcloud
# PUBLIC
# CURL::libcurl
# MbedTLS::mbedtls
# tinyxml2::tinyxml2
# )
# Compiler warnings
if(MSVC)
target_compile_options(nextcloud INTERFACE /W4)
else()
target_compile_options(nextcloud INTERFACE -Wall -Wextra -Wpedantic)
endif()
# Testing
if(BUILD_TESTING)
enable_testing()
add_subdirectory(tests)
endif()
# Examples
if(BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# Install rules
install(TARGETS nextcloud
EXPORT nextcloudTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(DIRECTORY include/
DESTINATION include
FILES_MATCHING PATTERN "*.hpp"
)
# Generate and install CMake config files
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/nextcloudConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfig.cmake"
INSTALL_DESTINATION lib/cmake/nextcloud
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfigVersion.cmake"
DESTINATION lib/cmake/nextcloud
)
install(EXPORT nextcloudTargets
FILE nextcloudTargets.cmake
NAMESPACE nextcloud::
DESTINATION lib/cmake/nextcloud
)
# pkg-config file
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/libnextcloud.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/libnextcloud.pc"
@ONLY
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnextcloud.pc"
DESTINATION lib/pkgconfig
)
# Print configuration summary
message(STATUS "")
message(STATUS "libnextcloud Configuration Summary:")
message(STATUS " Version: ${PROJECT_VERSION}")
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS " C++ standard: C++${CMAKE_CXX_STANDARD}")
message(STATUS " Shared libraries: ${BUILD_SHARED_LIBS}")
message(STATUS " Build tests: ${BUILD_TESTING}")
message(STATUS " Build examples: ${BUILD_EXAMPLES}")
message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}")
message(STATUS "")

288
shared/README.md Normal file
View File

@@ -0,0 +1,288 @@
# libnextcloud
Cross-platform C++17 library for Nextcloud connectivity on embedded devices and homebrew platforms.
## Overview
`libnextcloud` provides a clean, modern C++ API for interacting with Nextcloud servers. It's designed to work on resource-constrained devices like game console homebrew (Nintendo 3DS, Switch, Wii U) while also supporting desktop platforms.
**Status**: 🚧 In Development - Scaffolding complete, components being implemented
## Features (Planned)
-**Version Management**: Semantic versioning with compile-time and runtime queries
-**Type System**: Comprehensive error codes and data structures
- 🚧 **WebDAV Client**: HTTP/HTTPS communication with Nextcloud WebDAV API
- 🚧 **Authentication**: Basic Auth (OAuth2 planned)
- 🚧 **File Upload**: Streaming uploads with chunking and progress tracking
- 🚧 **Folder Management**: List, create, navigate remote folders
- 🚧 **Favorites & Recent**: Persistent user preferences
## Requirements
### Build Tools
- **CMake** 3.15 or later
- **C++17 compiler**: GCC 7+, Clang 5+, MSVC 2017+
### Dependencies
**Required** (when implementation complete):
- libcurl 7.68+
- mbedTLS 2.16+
- tinyxml2 9.0+
**Testing**:
- Google Test 1.11+
**Header-Only**:
- nlohmann/json 3.10+ (for configuration, future)
### Platform Support
| Platform | Status | Notes |
|----------|--------|-------|
| Linux | ✅ Development | Primary development platform |
| Nintendo 3DS | ✅ Planned | Via devkitARM in container |
| Nintendo Switch | 🔜 Planned | |
| Wii U | 🔜 Planned | |
| PlayStation Vita | 🔜 Planned | |
| Windows | 🔜 Planned | |
| macOS | 🔜 Planned | |
## Quick Start
### Building
```bash
# Configure (modern CMake style)
cmake -S . -B build
# Build
cmake --build build
# Run tests
cmake --build build --target test
# or with CTest for detailed output:
# ctest --test-dir build --output-on-failure
```
### Using in Your Project
#### CMake
```cmake
find_package(nextcloud REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app nextcloud::nextcloud)
```
#### pkg-config
```bash
g++ -std=c++17 main.cpp $(pkg-config --cflags --libs libnextcloud)
```
### Basic Usage
```cpp
#include <nextcloud/version.hpp>
#include <nextcloud/types.hpp>
#include <iostream>
int main() {
// Get library version
std::cout << "libnextcloud v" << nextcloud::getVersionString() << std::endl;
// Check version compatibility
if (nextcloud::isVersionAtLeast(0, 1, 0)) {
std::cout << "Version is compatible!" << std::endl;
}
// Use error types
nextcloud::NextcloudError error = nextcloud::NextcloudError::Success;
std::cout << "Status: " << nextcloud::errorToString(error) << std::endl;
return 0;
}
```
## Project Structure
```
shared/
├── CMakeLists.txt # Build configuration
├── README.md # This file
├── libnextcloud.pc.in # pkg-config template
├── nextcloudConfig.cmake.in # CMake config template
├── include/
│ └── nextcloud/
│ ├── version.hpp # Version information
│ ├── types.hpp # Common types and errors
│ ├── webdav_client.hpp # (Coming soon)
│ ├── auth.hpp # (Coming soon)
│ ├── upload_manager.hpp # (Coming soon)
│ ├── folder_manager.hpp # (Coming soon)
│ └── config.hpp # (Coming soon)
├── src/ # Implementation files (future)
├── tests/
│ ├── CMakeLists.txt
│ └── smoke_test.cpp # Basic tests
├── examples/ # Usage examples (future)
└── docs/ # Documentation (future)
```
## Building for Platforms
### Linux (Development)
```bash
mkdir build && cd build
cmake ..
make
make test
```
### Nintendo 3DS (Container)
```bash
# From project root
podman run --rm -v .:/project:z tomusan/devkitarm-3ds:latest \
bash -c "cd /project/shared && mkdir -p build && cd build && cmake .. && make"
```
## API Documentation
### Version Information
```cpp
#include <nextcloud/version.hpp>
// Constants
nextcloud::VERSION_MAJOR // 0
nextcloud::VERSION_MINOR // 1
nextcloud::VERSION_PATCH // 0
nextcloud::VERSION_STRING // "0.1.0"
// Functions
std::string getVersionString();
void getVersion(int& major, int& minor, int& patch);
bool isVersionAtLeast(int major, int minor, int patch);
```
### Error Handling
```cpp
#include <nextcloud/types.hpp>
// Error codes
enum class NextcloudError {
Success,
NetworkError,
AuthenticationFailed,
ServerError,
FileNotFound,
// ... more error codes
};
// Convert to string
const char* errorToString(NextcloudError error);
// Result type
nextcloud::Result<int> result;
if (result.isSuccess()) {
// Use result.value
} else {
std::cerr << result.errorMessage() << std::endl;
}
```
### Data Structures
```cpp
// Upload progress
struct UploadProgress {
std::string filename;
uint64_t bytesUploaded;
uint64_t totalBytes;
float percentComplete;
float bytesPerSecond;
int secondsRemaining;
};
// File information
struct FileInfo {
std::string name;
std::string path;
bool isDirectory;
uint64_t size;
std::time_t modifiedTime;
std::string contentType;
};
// Folder information
struct FolderInfo {
std::string path;
std::string displayName;
std::time_t lastUsed;
bool isFavorite;
};
```
## Testing
```bash
# Run all tests
cd build
ctest --output-on-failure
# Or use the custom target
make run_tests
# Run specific test
./tests/smoke_test
```
## Development Status
-**Phase 1: Scaffolding** - Complete
- Directory structure
- CMake build system
- Version and types headers
- Google Test integration
- Basic smoke tests
- 🚧 **Phase 2: WebDAV Client** - Not started
- Issue #8
- 🚧 **Phase 3: Authentication** - Not started
- Issue #9
- 🚧 **Phase 4: Upload Manager** - Not started
- Issue #10
- 🚧 **Phase 5: Folder Management** - Not started
- Issue #11
- 🚧 **Phase 6: Favorites & Recent** - Not started
- Issue #12
- 🚧 **Phase 7: Testing & Docs** - Not started
- Issue #13
## Contributing
See [CONTRIBUTING.md](../CONTRIBUTING.md) in the project root.
## License
[License TBD - to be determined]
## Related Documentation
- [Project Plan](../.plans/CreateLibNextcloud.md)
- [Issue #25](https://git.tomusan.com/maj/nextcloud-share/issues/25) - Initialize libnextcloud
---
**Note**: This library is in active development. The API is subject to change until version 1.0.0.

View File

@@ -0,0 +1,176 @@
#ifndef NEXTCLOUD_TYPES_HPP
#define NEXTCLOUD_TYPES_HPP
#include <string>
#include <cstdint>
#include <ctime>
namespace nextcloud {
/**
* @brief Error codes for Nextcloud operations
*/
enum class NextcloudError {
Success = 0,
// Network errors
NetworkError,
ConnectionFailed,
Timeout,
SSLError,
// Authentication errors
AuthenticationFailed,
InvalidCredentials,
Unauthorized,
// Server errors
ServerError,
ServiceUnavailable,
InsufficientStorage,
// File/path errors
FileNotFound,
PathNotFound,
InvalidPath,
FileAlreadyExists,
PathAlreadyExists,
// Operation errors
OperationFailed,
OperationCancelled,
InvalidOperation,
// Parsing/format errors
ParseError,
InvalidResponse,
UnsupportedFormat,
// Configuration errors
InvalidConfiguration,
MissingConfiguration,
// Unknown
Unknown
};
/**
* @brief Convert error code to human-readable string
* @param error The error code
* @return String description of the error
*/
inline const char* errorToString(NextcloudError error) {
switch (error) {
case NextcloudError::Success: return "Success";
case NextcloudError::NetworkError: return "Network error";
case NextcloudError::ConnectionFailed: return "Connection failed";
case NextcloudError::Timeout: return "Operation timed out";
case NextcloudError::SSLError: return "SSL/TLS error";
case NextcloudError::AuthenticationFailed: return "Authentication failed";
case NextcloudError::InvalidCredentials: return "Invalid credentials";
case NextcloudError::Unauthorized: return "Unauthorized";
case NextcloudError::ServerError: return "Server error";
case NextcloudError::ServiceUnavailable: return "Service unavailable";
case NextcloudError::InsufficientStorage: return "Insufficient storage";
case NextcloudError::FileNotFound: return "File not found";
case NextcloudError::PathNotFound: return "Path not found";
case NextcloudError::InvalidPath: return "Invalid path";
case NextcloudError::FileAlreadyExists: return "File already exists";
case NextcloudError::PathAlreadyExists: return "Path already exists";
case NextcloudError::OperationFailed: return "Operation failed";
case NextcloudError::OperationCancelled: return "Operation cancelled";
case NextcloudError::InvalidOperation: return "Invalid operation";
case NextcloudError::ParseError: return "Parse error";
case NextcloudError::InvalidResponse: return "Invalid response";
case NextcloudError::UnsupportedFormat: return "Unsupported format";
case NextcloudError::InvalidConfiguration: return "Invalid configuration";
case NextcloudError::MissingConfiguration: return "Missing configuration";
case NextcloudError::Unknown: return "Unknown error";
default: return "Unrecognized error";
}
}
/**
* @brief Result type for operations that can fail
* @tparam T The success value type
*/
template<typename T>
struct Result {
NextcloudError error;
T value;
/**
* @brief Check if the operation was successful
* @return True if no error occurred
*/
bool isSuccess() const { return error == NextcloudError::Success; }
/**
* @brief Check if an error occurred
* @return True if an error occurred
*/
bool isError() const { return error != NextcloudError::Success; }
/**
* @brief Get error message
* @return Human-readable error description
*/
const char* errorMessage() const { return errorToString(error); }
};
/**
* @brief Upload progress information
*/
struct UploadProgress {
std::string filename; ///< Name of file being uploaded
uint64_t bytesUploaded; ///< Number of bytes uploaded so far
uint64_t totalBytes; ///< Total file size in bytes
float percentComplete; ///< Completion percentage (0.0 - 100.0)
float bytesPerSecond; ///< Current transfer speed
int secondsRemaining; ///< Estimated seconds remaining (-1 if unknown)
};
/**
* @brief Information about a file or directory
*/
struct FileInfo {
std::string name; ///< File or directory name
std::string path; ///< Full path on server
bool isDirectory; ///< True if this is a directory
uint64_t size; ///< File size in bytes (0 for directories)
std::time_t modifiedTime; ///< Last modification time (Unix timestamp)
std::string contentType; ///< MIME type (e.g., "image/png")
std::string etag; ///< ETag for change detection
};
/**
* @brief Information about a favorite or recent folder
*/
struct FolderInfo {
std::string path; ///< Full path on server
std::string displayName; ///< User-friendly name
std::time_t lastUsed; ///< Last access time (Unix timestamp)
bool isFavorite; ///< True if marked as favorite
};
/**
* @brief HTTP response information
*/
struct HttpResponse {
int statusCode; ///< HTTP status code (e.g., 200, 404)
std::string body; ///< Response body
std::string contentType; ///< Content-Type header value
NextcloudError error; ///< Error code if request failed
/**
* @brief Check if response indicates success (2xx status code)
* @return True if status code is 200-299
*/
bool isSuccess() const {
return statusCode >= 200 && statusCode < 300 && error == NextcloudError::Success;
}
};
} // namespace nextcloud
#endif // NEXTCLOUD_TYPES_HPP

View File

@@ -0,0 +1,57 @@
#ifndef NEXTCLOUD_VERSION_HPP
#define NEXTCLOUD_VERSION_HPP
#include <string>
namespace nextcloud {
// Semantic versioning
constexpr int VERSION_MAJOR = 0;
constexpr int VERSION_MINOR = 1;
constexpr int VERSION_PATCH = 0;
// Build metadata
constexpr const char* VERSION_STRING = "0.1.0";
constexpr const char* BUILD_DATE = __DATE__;
constexpr const char* BUILD_TIME = __TIME__;
/**
* @brief Get the library version as a string
* @return Version string in format "MAJOR.MINOR.PATCH"
*/
inline std::string getVersionString() {
return VERSION_STRING;
}
/**
* @brief Get the library version components
* @param major Output parameter for major version
* @param minor Output parameter for minor version
* @param patch Output parameter for patch version
*/
inline void getVersion(int& major, int& minor, int& patch) {
major = VERSION_MAJOR;
minor = VERSION_MINOR;
patch = VERSION_PATCH;
}
/**
* @brief Check if the library version is at least the specified version
* @param major Required major version
* @param minor Required minor version
* @param patch Required patch version
* @return True if current version >= required version
*/
inline bool isVersionAtLeast(int major, int minor, int patch) {
if (VERSION_MAJOR > major) return true;
if (VERSION_MAJOR < major) return false;
if (VERSION_MINOR > minor) return true;
if (VERSION_MINOR < minor) return false;
return VERSION_PATCH >= patch;
}
} // namespace nextcloud
#endif // NEXTCLOUD_VERSION_HPP

11
shared/libnextcloud.pc.in Normal file
View File

@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: libnextcloud
Description: Cross-platform C++ library for Nextcloud connectivity
Version: @PROJECT_VERSION@
Requires:
Cflags: -I${includedir}
Libs: -L${libdir} -lnextcloud

View File

@@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/nextcloudTargets.cmake")
check_required_components(nextcloud)

View File

@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.15)
# Find Google Test
find_package(GTest REQUIRED)
# Include Google Test helpers
include(GoogleTest)
# Test executable
add_executable(smoke_test
smoke_test.cpp
)
# Link against the library and GTest
target_link_libraries(smoke_test
PRIVATE
nextcloud
GTest::GTest
GTest::Main
)
# Discover and register tests
gtest_discover_tests(smoke_test)
# Add custom target to run tests
add_custom_target(run_tests
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS smoke_test
COMMENT "Running tests..."
)

140
shared/tests/smoke_test.cpp Normal file
View File

@@ -0,0 +1,140 @@
#include <gtest/gtest.h>
#include <nextcloud/version.hpp>
#include <nextcloud/types.hpp>
/**
* @file smoke_test.cpp
* @brief Basic smoke tests to verify library setup
*
* These tests ensure that the library headers compile correctly
* and basic functionality works as expected.
*/
namespace {
// Test version information
TEST(VersionTest, VersionConstants) {
EXPECT_EQ(nextcloud::VERSION_MAJOR, 0);
EXPECT_EQ(nextcloud::VERSION_MINOR, 1);
EXPECT_EQ(nextcloud::VERSION_PATCH, 0);
EXPECT_STREQ(nextcloud::VERSION_STRING, "0.1.0");
}
TEST(VersionTest, GetVersionString) {
std::string version = nextcloud::getVersionString();
EXPECT_EQ(version, "0.1.0");
}
TEST(VersionTest, GetVersionComponents) {
int major, minor, patch;
nextcloud::getVersion(major, minor, patch);
EXPECT_EQ(major, 0);
EXPECT_EQ(minor, 1);
EXPECT_EQ(patch, 0);
}
TEST(VersionTest, IsVersionAtLeast) {
// Current version is 0.1.0
EXPECT_TRUE(nextcloud::isVersionAtLeast(0, 0, 0));
EXPECT_TRUE(nextcloud::isVersionAtLeast(0, 1, 0));
EXPECT_FALSE(nextcloud::isVersionAtLeast(0, 2, 0));
EXPECT_FALSE(nextcloud::isVersionAtLeast(1, 0, 0));
}
// Test error types
TEST(TypesTest, ErrorToString) {
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::Success), "Success");
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::NetworkError), "Network error");
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::AuthenticationFailed), "Authentication failed");
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::FileNotFound), "File not found");
}
TEST(TypesTest, ResultSuccess) {
nextcloud::Result<int> result;
result.error = nextcloud::NextcloudError::Success;
result.value = 42;
EXPECT_TRUE(result.isSuccess());
EXPECT_FALSE(result.isError());
EXPECT_EQ(result.value, 42);
}
TEST(TypesTest, ResultError) {
nextcloud::Result<std::string> result;
result.error = nextcloud::NextcloudError::NetworkError;
result.value = "";
EXPECT_FALSE(result.isSuccess());
EXPECT_TRUE(result.isError());
EXPECT_STREQ(result.errorMessage(), "Network error");
}
TEST(TypesTest, UploadProgressStruct) {
nextcloud::UploadProgress progress;
progress.filename = "test.txt";
progress.bytesUploaded = 50;
progress.totalBytes = 100;
progress.percentComplete = 50.0f;
progress.bytesPerSecond = 1024.0f;
progress.secondsRemaining = 1;
EXPECT_EQ(progress.filename, "test.txt");
EXPECT_EQ(progress.bytesUploaded, 50);
EXPECT_EQ(progress.totalBytes, 100);
EXPECT_FLOAT_EQ(progress.percentComplete, 50.0f);
}
TEST(TypesTest, FileInfoStruct) {
nextcloud::FileInfo file;
file.name = "document.pdf";
file.path = "/Documents/document.pdf";
file.isDirectory = false;
file.size = 1024;
file.modifiedTime = 1234567890;
file.contentType = "application/pdf";
EXPECT_EQ(file.name, "document.pdf");
EXPECT_EQ(file.path, "/Documents/document.pdf");
EXPECT_FALSE(file.isDirectory);
EXPECT_EQ(file.size, 1024);
}
TEST(TypesTest, FolderInfoStruct) {
nextcloud::FolderInfo folder;
folder.path = "/Photos";
folder.displayName = "My Photos";
folder.lastUsed = 1234567890;
folder.isFavorite = true;
EXPECT_EQ(folder.path, "/Photos");
EXPECT_EQ(folder.displayName, "My Photos");
EXPECT_TRUE(folder.isFavorite);
}
TEST(TypesTest, HttpResponseSuccess) {
nextcloud::HttpResponse response;
response.statusCode = 200;
response.body = "OK";
response.contentType = "text/plain";
response.error = nextcloud::NextcloudError::Success;
EXPECT_TRUE(response.isSuccess());
EXPECT_EQ(response.statusCode, 200);
}
TEST(TypesTest, HttpResponseError) {
nextcloud::HttpResponse response;
response.statusCode = 404;
response.body = "Not Found";
response.error = nextcloud::NextcloudError::FileNotFound;
EXPECT_FALSE(response.isSuccess());
EXPECT_EQ(response.statusCode, 404);
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}