diff --git a/.env.storage.example b/.env.storage.example new file mode 100644 index 0000000..54126ef --- /dev/null +++ b/.env.storage.example @@ -0,0 +1,38 @@ +# OpenAccounting Storage Configuration +# Copy this file to .env and modify as needed + +# Database Configuration +OA_DATABASEDRIVER=sqlite +OA_DATABASEFILE=./openaccounting.db +OA_ADDRESS=localhost +OA_PORT=8080 +OA_APIPREFIX=/api/v1 + +# Storage Backend Configuration +# Options: local, s3, b2 +OA_STORAGE_BACKEND=local + +# Local Storage Configuration +OA_STORAGE_LOCAL_ROOTDIR=./uploads +OA_STORAGE_LOCAL_BASEURL= + +# Amazon S3 Storage Configuration (uncomment if using S3) +# OA_STORAGE_S3_REGION=us-east-1 +# OA_STORAGE_S3_BUCKET=my-openaccounting-attachments +# OA_STORAGE_S3_PREFIX=attachments +# OA_STORAGE_S3_ACCESSKEYID=AKIA... +# OA_STORAGE_S3_SECRETACCESSKEY=... +# OA_STORAGE_S3_ENDPOINT= +# OA_STORAGE_S3_PATHSTYLE=false + +# Backblaze B2 Storage Configuration (uncomment if using B2) +# OA_STORAGE_B2_ACCOUNTID=your-b2-account-id +# OA_STORAGE_B2_APPLICATIONKEY=your-b2-application-key +# OA_STORAGE_B2_BUCKET=my-openaccounting-attachments +# OA_STORAGE_B2_PREFIX=attachments + +# Email Configuration (optional) +# OA_MAILGUNDOMAIN= +# OA_MAILGUNKEY= +# OA_MAILGUNEMAIL= +# OA_MAILGUNSENDER= \ No newline at end of file diff --git a/.gitignore b/.gitignore index a4c3eb7..bb4d844 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,6 @@ config.json *.csr *.sublime-project *.sublime-workspace +.vscode/ +server +attachments/ diff --git a/README.md b/README.md index 77bc0d9..0fee0f6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Open Accounting Server is a modern financial accounting system built with Go, fe - **GORM Integration**: Modern ORM with SQLite and MySQL support - **Viper Configuration**: Flexible config management with environment variables +- **Modular Storage**: S3-compatible attachment storage (Local, AWS S3, Backblaze B2, Cloudflare R2, MinIO) - **Docker Ready**: Containerized deployment with multi-stage builds - **SQLite Support**: Easy local development and testing - **Security**: Environment variable support for sensitive data @@ -81,6 +82,35 @@ All configuration can be overridden with environment variables using the `OA_` p | `OA_MAILGUN_EMAIL` | MailgunEmail | | Mailgun email | | `OA_MAILGUN_SENDER` | MailgunSender | | Mailgun sender name | +#### Storage Configuration + +| Environment Variable | Config Field | Default | Description | +|---------------------|--------------|---------|-------------| +| `OA_STORAGE_BACKEND` | Storage.Backend | `local` | Storage backend: `local` or `s3` | + +**Local Storage** +| Environment Variable | Config Field | Default | Description | +|---------------------|--------------|---------|-------------| +| `OA_STORAGE_LOCAL_ROOTDIR` | Storage.Local.RootDir | `./uploads` | Root directory for file storage | +| `OA_STORAGE_LOCAL_BASEURL` | Storage.Local.BaseURL | | Base URL for serving files | + +**S3-Compatible Storage** (AWS S3, Backblaze B2, Cloudflare R2, MinIO) +| Environment Variable | Config Field | Default | Description | +|---------------------|--------------|---------|-------------| +| `OA_STORAGE_S3_REGION` | Storage.S3.Region | | Region (use "auto" for Cloudflare R2) | +| `OA_STORAGE_S3_BUCKET` | Storage.S3.Bucket | | Bucket name | +| `OA_STORAGE_S3_PREFIX` | Storage.S3.Prefix | | Optional prefix for all objects | +| `OA_STORAGE_S3_ACCESSKEYID` | Storage.S3.AccessKeyID | | Access Key ID ⚠️ | +| `OA_STORAGE_S3_SECRETACCESSKEY` | Storage.S3.SecretAccessKey | | Secret Access Key ⚠️ | +| `OA_STORAGE_S3_ENDPOINT` | Storage.S3.Endpoint | | Custom endpoint (see examples below) | +| `OA_STORAGE_S3_PATHSTYLE` | Storage.S3.PathStyle | `false` | Use path-style addressing | + +**S3-Compatible Service Endpoints:** +- **AWS S3**: Leave endpoint empty, set appropriate region +- **Backblaze B2**: `https://s3.us-west-004.backblazeb2.com` (replace region as needed) +- **Cloudflare R2**: `https://.r2.cloudflarestorage.com` +- **MinIO**: `http://localhost:9000` (or your MinIO server URL) + ⚠️ **Security**: Always use environment variables for sensitive data like passwords and API keys. ### Configuration Examples @@ -109,6 +139,51 @@ export OA_MAILGUN_KEY=key-abc123 OA_DATABASE_DRIVER=mysql OA_PASSWORD=secret OA_MAILGUN_KEY=key-123 ./server ``` +#### Storage Configuration Examples +```bash +# Local storage (default) +export OA_STORAGE_BACKEND=local +export OA_STORAGE_LOCAL_ROOTDIR=./uploads +./server + +# AWS S3 +export OA_STORAGE_BACKEND=s3 +export OA_STORAGE_S3_REGION=us-west-2 +export OA_STORAGE_S3_BUCKET=my-app-attachments +export OA_STORAGE_S3_ACCESSKEYID=your-access-key +export OA_STORAGE_S3_SECRETACCESSKEY=your-secret-key +./server + +# Backblaze B2 (S3-compatible) +export OA_STORAGE_BACKEND=s3 +export OA_STORAGE_S3_REGION=us-west-004 +export OA_STORAGE_S3_BUCKET=my-app-attachments +export OA_STORAGE_S3_ACCESSKEYID=your-b2-key-id +export OA_STORAGE_S3_SECRETACCESSKEY=your-b2-application-key +export OA_STORAGE_S3_ENDPOINT=https://s3.us-west-004.backblazeb2.com +export OA_STORAGE_S3_PATHSTYLE=true +./server + +# Cloudflare R2 +export OA_STORAGE_BACKEND=s3 +export OA_STORAGE_S3_REGION=auto +export OA_STORAGE_S3_BUCKET=my-app-attachments +export OA_STORAGE_S3_ACCESSKEYID=your-r2-access-key +export OA_STORAGE_S3_SECRETACCESSKEY=your-r2-secret-key +export OA_STORAGE_S3_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com +./server + +# MinIO (self-hosted) +export OA_STORAGE_BACKEND=s3 +export OA_STORAGE_S3_REGION=us-east-1 +export OA_STORAGE_S3_BUCKET=my-app-attachments +export OA_STORAGE_S3_ACCESSKEYID=minioadmin +export OA_STORAGE_S3_SECRETACCESSKEY=minioadmin +export OA_STORAGE_S3_ENDPOINT=http://localhost:9000 +export OA_STORAGE_S3_PATHSTYLE=true +./server +``` + #### Docker ```bash # SQLite with volume mount @@ -123,6 +198,25 @@ docker run -p 8080:8080 \ -e OA_DATABASE_ADDRESS=mysql:3306 \ -e OA_PASSWORD=secret \ openaccounting-server:latest + +# With AWS S3 storage +docker run -p 8080:8080 \ + -e OA_STORAGE_BACKEND=s3 \ + -e OA_STORAGE_S3_REGION=us-west-2 \ + -e OA_STORAGE_S3_BUCKET=my-attachments \ + -e OA_STORAGE_S3_ACCESSKEYID=your-key \ + -e OA_STORAGE_S3_SECRETACCESSKEY=your-secret \ + openaccounting-server:latest + +# With Cloudflare R2 storage +docker run -p 8080:8080 \ + -e OA_STORAGE_BACKEND=s3 \ + -e OA_STORAGE_S3_REGION=auto \ + -e OA_STORAGE_S3_BUCKET=my-attachments \ + -e OA_STORAGE_S3_ACCESSKEYID=your-r2-key \ + -e OA_STORAGE_S3_SECRETACCESSKEY=your-r2-secret \ + -e OA_STORAGE_S3_ENDPOINT=https://account-id.r2.cloudflarestorage.com \ + openaccounting-server:latest ``` ## Database Setup diff --git a/STORAGE.md b/STORAGE.md new file mode 100644 index 0000000..4e556fe --- /dev/null +++ b/STORAGE.md @@ -0,0 +1,239 @@ +# Modular Storage System + +The OpenAccounting server now supports multiple storage backends for file attachments. This allows you to choose between local filesystem storage for simple deployments or cloud storage for production/multi-user environments. + +## Supported Storage Backends + +### 1. Local Filesystem Storage +Perfect for self-hosted deployments or development environments. + +**Configuration:** +```json +{ + "storage": { + "backend": "local", + "local": { + "root_dir": "./uploads", + "base_url": "https://yourapp.com/files" + } + } +} +``` + +**Environment Variables:** +```bash +OA_STORAGE_BACKEND=local +OA_STORAGE_LOCAL_ROOT_DIR=./uploads +OA_STORAGE_LOCAL_BASE_URL=https://yourapp.com/files +``` + +### 2. Amazon S3 Storage +Reliable cloud storage for production deployments. + +**Configuration:** +```json +{ + "storage": { + "backend": "s3", + "s3": { + "region": "us-east-1", + "bucket": "my-openaccounting-attachments", + "prefix": "attachments", + "access_key_id": "AKIA...", + "secret_access_key": "...", + "endpoint": "", + "path_style": false + } + } +} +``` + +**Environment Variables:** +```bash +OA_STORAGE_BACKEND=s3 +OA_STORAGE_S3_REGION=us-east-1 +OA_STORAGE_S3_BUCKET=my-openaccounting-attachments +OA_STORAGE_S3_PREFIX=attachments +OA_STORAGE_S3_ACCESS_KEY_ID=AKIA... +OA_STORAGE_S3_SECRET_ACCESS_KEY=... +``` + +**Features:** +- Automatic presigned URL generation +- Configurable expiry times +- Support for S3-compatible services (MinIO, DigitalOcean Spaces) +- IAM role support (leave credentials empty to use IAM) + +### 3. Backblaze B2 Storage +Cost-effective cloud storage alternative to S3. + +**Configuration:** +```json +{ + "storage": { + "backend": "b2", + "b2": { + "account_id": "your-b2-account-id", + "application_key": "your-b2-application-key", + "bucket": "my-openaccounting-attachments", + "prefix": "attachments" + } + } +} +``` + +**Environment Variables:** +```bash +OA_STORAGE_BACKEND=b2 +OA_STORAGE_B2_ACCOUNT_ID=your-b2-account-id +OA_STORAGE_B2_APPLICATION_KEY=your-b2-application-key +OA_STORAGE_B2_BUCKET=my-openaccounting-attachments +OA_STORAGE_B2_PREFIX=attachments +``` + +## API Endpoints + +The storage system provides both legacy and new endpoints: + +### New Storage-Agnostic Endpoints + +**Upload Attachment:** +``` +POST /api/v1/attachments +Content-Type: multipart/form-data + +transactionId: uuid +description: string (optional) +file: binary data +``` + +**Get Attachment Metadata:** +``` +GET /api/v1/attachments/{id} +``` + +**Get Download URL:** +``` +GET /api/v1/attachments/{id}/url +``` + +**Download File:** +``` +GET /api/v1/attachments/{id}?download=true +``` + +**Delete Attachment:** +``` +DELETE /api/v1/attachments/{id} +``` + +### Legacy Endpoints (Still Supported) +The original transaction-scoped endpoints remain available for backward compatibility: +- `GET/POST /api/v1/orgs/{orgId}/transactions/{transactionId}/attachments` + +## Security Features + +- **File type validation** - Only allowed MIME types are accepted +- **File size limits** - Configurable maximum file size (default 10MB) +- **Path traversal protection** - Prevents directory traversal attacks +- **Access control** - Files are linked to users and organizations +- **Presigned URLs** - Time-limited access for cloud storage + +## File Organization + +Files are automatically organized by date: +``` +uploads/ +├── 2025/ +│ ├── 01/ +│ │ ├── 15/ +│ │ │ ├── uuid1.pdf +│ │ │ └── uuid2.png +│ │ └── 16/ +│ │ └── uuid3.jpg +``` + +## Configuration Examples + +### Development (Local Storage) +```json +{ + "storage": { + "backend": "local", + "local": { + "root_dir": "./dev-uploads" + } + } +} +``` + +### Production (S3 with IAM) +```json +{ + "storage": { + "backend": "s3", + "s3": { + "region": "us-west-2", + "bucket": "prod-openaccounting-files", + "prefix": "attachments" + } + } +} +``` + +### Cost-Optimized (Backblaze B2) +```json +{ + "storage": { + "backend": "b2", + "b2": { + "account_id": "${B2_ACCOUNT_ID}", + "application_key": "${B2_APP_KEY}", + "bucket": "openaccounting-prod" + } + } +} +``` + +## Migration Between Storage Backends + +When changing storage backends, existing attachments will remain in the old storage location. The database records contain the storage path, so files can be accessed until migrated. + +To migrate: +1. Update configuration to new backend +2. Restart server +3. New uploads will use the new backend +4. Optional: Run migration script to move existing files + +## Environment-Specific Considerations + +### Self-Hosted +- Use local storage for simplicity +- Ensure backup strategy includes upload directory +- Consider disk space management + +### Cloud Deployment +- Use S3 or B2 for reliability and scalability +- Configure proper IAM policies +- Enable versioning and lifecycle policies + +### Multi-Region +- Use cloud storage with appropriate region selection +- Consider CDN integration for better performance + +## Troubleshooting + +**Storage backend not initialized:** +- Check configuration syntax +- Verify credentials for cloud backends +- Ensure storage directories/buckets exist + +**Permission denied:** +- Check file system permissions for local storage +- Verify IAM policies for S3 +- Confirm B2 application key permissions + +**Large file uploads failing:** +- Check `MaxFileSize` configuration +- Verify network timeouts +- Consider multipart upload for large files \ No newline at end of file diff --git a/config.b2.json.sample b/config.b2.json.sample new file mode 100644 index 0000000..007769e --- /dev/null +++ b/config.b2.json.sample @@ -0,0 +1,17 @@ +{ + "weburl": "https://yourapp.com", + "address": "localhost", + "port": 8080, + "apiprefix": "/api/v1", + "databasedriver": "sqlite", + "databasefile": "./openaccounting.db", + "storage": { + "backend": "b2", + "b2": { + "account_id": "your-b2-account-id", + "application_key": "your-b2-application-key", + "bucket": "my-openaccounting-attachments", + "prefix": "attachments" + } + } +} \ No newline at end of file diff --git a/config.s3.json.sample b/config.s3.json.sample new file mode 100644 index 0000000..c47136f --- /dev/null +++ b/config.s3.json.sample @@ -0,0 +1,20 @@ +{ + "weburl": "https://yourapp.com", + "address": "localhost", + "port": 8080, + "apiprefix": "/api/v1", + "databasedriver": "sqlite", + "databasefile": "./openaccounting.db", + "storage": { + "backend": "s3", + "s3": { + "region": "us-east-1", + "bucket": "my-openaccounting-attachments", + "prefix": "attachments", + "access_key_id": "", + "secret_access_key": "", + "endpoint": "", + "path_style": false + } + } +} \ No newline at end of file diff --git a/config.storage.json.sample b/config.storage.json.sample new file mode 100644 index 0000000..1258c33 --- /dev/null +++ b/config.storage.json.sample @@ -0,0 +1,15 @@ +{ + "weburl": "https://yourapp.com", + "address": "localhost", + "port": 8080, + "apiprefix": "/api/v1", + "databasedriver": "sqlite", + "databasefile": "./openaccounting.db", + "storage": { + "backend": "local", + "local": { + "root_dir": "./uploads", + "base_url": "https://yourapp.com/files" + } + } +} \ No newline at end of file diff --git a/core/api/attachment.go b/core/api/attachment.go new file mode 100644 index 0000000..60ecb78 --- /dev/null +++ b/core/api/attachment.go @@ -0,0 +1,313 @@ +package api + +import ( + "fmt" + "io" + "mime/multipart" + "net/http" + "os" + "path/filepath" + "strings" + "time" + + "github.com/ant0ine/go-json-rest/rest" + "github.com/openaccounting/oa-server/core/model" + "github.com/openaccounting/oa-server/core/model/types" + "github.com/openaccounting/oa-server/core/util" +) + +const ( + MaxFileSize = 10 * 1024 * 1024 // 10MB + MaxFilesPerTx = 10 + AttachmentDir = "attachments" +) + +var AllowedMimeTypes = map[string]bool{ + "image/jpeg": true, + "image/png": true, + "image/gif": true, + "application/pdf": true, + "text/plain": true, + "text/csv": true, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": true, // .xlsx + "application/vnd.ms-excel": true, // .xls +} + +func PostAttachment(w rest.ResponseWriter, r *rest.Request) { + orgId := r.PathParam("orgId") + transactionId := r.PathParam("transactionId") + + if !util.IsValidUUID(orgId) || !util.IsValidUUID(transactionId) { + rest.Error(w, "Invalid UUID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + // Parse multipart form + err := r.ParseMultipartForm(MaxFileSize) + if err != nil { + rest.Error(w, "Failed to parse multipart form", http.StatusBadRequest) + return + } + + files := r.MultipartForm.File["files"] + if len(files) == 0 { + rest.Error(w, "No files provided", http.StatusBadRequest) + return + } + + if len(files) > MaxFilesPerTx { + rest.Error(w, fmt.Sprintf("Too many files. Maximum %d files allowed", MaxFilesPerTx), http.StatusBadRequest) + return + } + + // Verify transaction exists and user has permission + tx, err := model.Instance.GetTransaction(transactionId, orgId, user.Id) + if err != nil { + rest.Error(w, "Transaction not found or access denied", http.StatusNotFound) + return + } + if tx == nil { + rest.Error(w, "Transaction not found", http.StatusNotFound) + return + } + + var attachments []*types.Attachment + var description string + if desc := r.FormValue("description"); desc != "" { + description = desc + } + + for _, fileHeader := range files { + attachment, err := processFileUpload(fileHeader, transactionId, orgId, user.Id, description) + if err != nil { + // Clean up any successfully uploaded files + for _, att := range attachments { + os.Remove(att.FilePath) + } + rest.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Save attachment to database + createdAttachment, err := model.Instance.CreateAttachment(attachment) + if err != nil { + // Clean up file and any previously uploaded files + os.Remove(attachment.FilePath) + for _, att := range attachments { + os.Remove(att.FilePath) + } + rest.Error(w, "Failed to save attachment", http.StatusInternalServerError) + return + } + + attachments = append(attachments, createdAttachment) + } + + w.WriteJson(map[string]interface{}{ + "attachments": attachments, + "count": len(attachments), + }) +} + +func GetAttachments(w rest.ResponseWriter, r *rest.Request) { + orgId := r.PathParam("orgId") + transactionId := r.PathParam("transactionId") + + if !util.IsValidUUID(orgId) || !util.IsValidUUID(transactionId) { + rest.Error(w, "Invalid UUID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + attachments, err := model.Instance.GetAttachmentsByTransaction(transactionId, orgId, user.Id) + if err != nil { + rest.Error(w, "Failed to retrieve attachments", http.StatusInternalServerError) + return + } + + w.WriteJson(attachments) +} + +func GetAttachment(w rest.ResponseWriter, r *rest.Request) { + orgId := r.PathParam("orgId") + transactionId := r.PathParam("transactionId") + attachmentId := r.PathParam("attachmentId") + + if !util.IsValidUUID(orgId) || !util.IsValidUUID(transactionId) || !util.IsValidUUID(attachmentId) { + rest.Error(w, "Invalid UUID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + attachment, err := model.Instance.GetAttachment(attachmentId, transactionId, orgId, user.Id) + if err != nil { + rest.Error(w, "Attachment not found or access denied", http.StatusNotFound) + return + } + + w.WriteJson(attachment) +} + +func DownloadAttachment(w rest.ResponseWriter, r *rest.Request) { + orgId := r.PathParam("orgId") + transactionId := r.PathParam("transactionId") + attachmentId := r.PathParam("attachmentId") + + if !util.IsValidUUID(orgId) || !util.IsValidUUID(transactionId) || !util.IsValidUUID(attachmentId) { + rest.Error(w, "Invalid UUID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + attachment, err := model.Instance.GetAttachment(attachmentId, transactionId, orgId, user.Id) + if err != nil { + rest.Error(w, "Attachment not found or access denied", http.StatusNotFound) + return + } + + // Check if file exists + if _, err := os.Stat(attachment.FilePath); os.IsNotExist(err) { + rest.Error(w, "File not found on disk", http.StatusNotFound) + return + } + + // Set headers for file download + w.Header().Set("Content-Type", attachment.ContentType) + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", attachment.OriginalName)) + + // Open and serve file + file, err := os.Open(attachment.FilePath) + if err != nil { + rest.Error(w, "Failed to open file", http.StatusInternalServerError) + return + } + defer file.Close() + + io.Copy(w.(http.ResponseWriter), file) +} + +func DeleteAttachment(w rest.ResponseWriter, r *rest.Request) { + orgId := r.PathParam("orgId") + transactionId := r.PathParam("transactionId") + attachmentId := r.PathParam("attachmentId") + + if !util.IsValidUUID(orgId) || !util.IsValidUUID(transactionId) || !util.IsValidUUID(attachmentId) { + rest.Error(w, "Invalid UUID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + err := model.Instance.DeleteAttachment(attachmentId, transactionId, orgId, user.Id) + if err != nil { + rest.Error(w, "Failed to delete attachment or access denied", http.StatusInternalServerError) + return + } + + w.WriteJson(map[string]string{"status": "deleted"}) +} + +func processFileUpload(fileHeader *multipart.FileHeader, transactionId, orgId, userId, description string) (*types.Attachment, error) { + // Validate file size + if fileHeader.Size > MaxFileSize { + return nil, fmt.Errorf("file too large. Maximum size is %d bytes", MaxFileSize) + } + + // Open uploaded file + file, err := fileHeader.Open() + if err != nil { + return nil, fmt.Errorf("failed to open uploaded file: %v", err) + } + defer file.Close() + + // Validate file type from header + contentType := fileHeader.Header.Get("Content-Type") + if !AllowedMimeTypes[contentType] { + return nil, fmt.Errorf("file type %s not allowed", contentType) + } + + // Validate file type by detecting content (more secure) + buffer := make([]byte, 512) + n, err := file.Read(buffer) + if err != nil { + return nil, fmt.Errorf("failed to read file for content detection: %v", err) + } + + // Reset file pointer to beginning + if _, err := file.Seek(0, 0); err != nil { + return nil, fmt.Errorf("failed to reset file pointer: %v", err) + } + + detectedType := http.DetectContentType(buffer[:n]) + if !AllowedMimeTypes[detectedType] { + return nil, fmt.Errorf("detected file type %s not allowed (header claimed %s)", detectedType, contentType) + } + + // Generate unique filename + attachmentId := util.NewUUID() + ext := filepath.Ext(fileHeader.Filename) + fileName := attachmentId + ext + + // Create attachments directory if it doesn't exist + uploadDir := filepath.Join(AttachmentDir, orgId, transactionId) + if err := os.MkdirAll(uploadDir, 0755); err != nil { + return nil, fmt.Errorf("failed to create upload directory: %v", err) + } + + // Create file path + filePath := filepath.Join(uploadDir, fileName) + + // Create destination file + dst, err := os.Create(filePath) + if err != nil { + return nil, fmt.Errorf("failed to create destination file: %v", err) + } + defer dst.Close() + + // Copy file contents + if _, err := io.Copy(dst, file); err != nil { + return nil, fmt.Errorf("failed to save file: %v", err) + } + + // Create attachment object + attachment := &types.Attachment{ + Id: attachmentId, + TransactionId: transactionId, + OrgId: orgId, + UserId: userId, + FileName: fileName, + OriginalName: fileHeader.Filename, + ContentType: contentType, + FileSize: fileHeader.Size, + FilePath: filePath, + Description: description, + Uploaded: time.Now(), + Deleted: false, + } + + return attachment, nil +} + +func sanitizeFilename(filename string) string { + // Remove potentially dangerous characters + filename = strings.ReplaceAll(filename, "..", "") + filename = strings.ReplaceAll(filename, "/", "") + filename = strings.ReplaceAll(filename, "\\", "") + filename = strings.ReplaceAll(filename, "\x00", "") // null bytes + filename = strings.ReplaceAll(filename, "\r", "") // carriage return + filename = strings.ReplaceAll(filename, "\n", "") // newline + + // Limit filename length + if len(filename) > 255 { + ext := filepath.Ext(filename) + base := filename[:255-len(ext)] + filename = base + ext + } + + return filename +} \ No newline at end of file diff --git a/core/api/attachment_integration_test.go b/core/api/attachment_integration_test.go new file mode 100644 index 0000000..a8b2fca --- /dev/null +++ b/core/api/attachment_integration_test.go @@ -0,0 +1,306 @@ +package api + +import ( + "io" + "os" + "path/filepath" + "testing" + "time" + + "github.com/openaccounting/oa-server/core/model" + "github.com/openaccounting/oa-server/core/model/types" + "github.com/openaccounting/oa-server/core/util" + "github.com/openaccounting/oa-server/core/util/id" + "github.com/openaccounting/oa-server/database" + "github.com/stretchr/testify/assert" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func setupTestDatabase(t *testing.T) (*gorm.DB, func()) { + // Create temporary database file + tmpDir := t.TempDir() + dbPath := filepath.Join(tmpDir, "test.db") + + db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to open database: %v", err) + } + + // Set global DB for database package + database.DB = db + + // Run migrations + err = database.AutoMigrate() + if err != nil { + t.Fatalf("Failed to run auto migrations: %v", err) + } + + err = database.Migrate() + if err != nil { + t.Fatalf("Failed to run custom migrations: %v", err) + } + + // Cleanup function + cleanup := func() { + sqlDB, _ := db.DB() + if sqlDB != nil { + sqlDB.Close() + } + os.RemoveAll(tmpDir) + } + + return db, cleanup +} + +func setupTestData(t *testing.T, db *gorm.DB) (orgID, userID, transactionID string) { + // Use hardcoded UUIDs without dashes for hex format + orgID = "550e8400e29b41d4a716446655440000" + userID = "550e8400e29b41d4a716446655440001" + transactionID = "550e8400e29b41d4a716446655440002" + accountID := "550e8400e29b41d4a716446655440003" + + // Insert test data using raw SQL for reliability + now := time.Now() + + // Insert org + err := db.Exec("INSERT INTO orgs (id, inserted, updated, name, currency, `precision`, timezone) VALUES (UNHEX(?), ?, ?, ?, ?, ?, ?)", + orgID, now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), "Test Org", "USD", 2, "UTC").Error + if err != nil { + t.Fatalf("Failed to insert org: %v", err) + } + + // Insert user + err = db.Exec("INSERT INTO users (id, inserted, updated, firstName, lastName, email, passwordHash, agreeToTerms, passwordReset, emailVerified, emailVerifyCode, signupSource) VALUES (UNHEX(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + userID, now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), "Test", "User", "test@example.com", "hashedpassword", true, "", true, "", "test").Error + if err != nil { + t.Fatalf("Failed to insert user: %v", err) + } + + // Insert user-org relationship + err = db.Exec("INSERT INTO user_orgs (userId, orgId, admin) VALUES (UNHEX(?), UNHEX(?), ?)", + userID, orgID, false).Error + if err != nil { + t.Fatalf("Failed to insert user-org: %v", err) + } + + // Insert account + err = db.Exec("INSERT INTO accounts (id, orgId, inserted, updated, name, parent, currency, `precision`, debitBalance) VALUES (UNHEX(?), UNHEX(?), ?, ?, ?, ?, ?, ?, ?)", + accountID, orgID, now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), "Test Account", []byte{}, "USD", 2, true).Error + if err != nil { + t.Fatalf("Failed to insert account: %v", err) + } + + // Insert transaction + err = db.Exec("INSERT INTO transactions (id, orgId, userId, inserted, updated, date, description, data, deleted) VALUES (UNHEX(?), UNHEX(?), UNHEX(?), ?, ?, ?, ?, ?, ?)", + transactionID, orgID, userID, now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), "Test Transaction", "", false).Error + if err != nil { + t.Fatalf("Failed to insert transaction: %v", err) + } + + // Insert split + err = db.Exec("INSERT INTO splits (transactionId, accountId, date, inserted, updated, amount, nativeAmount, deleted) VALUES (UNHEX(?), UNHEX(?), ?, ?, ?, ?, ?, ?)", + transactionID, accountID, now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), now.UnixNano()/int64(time.Millisecond), 100, 100, false).Error + if err != nil { + t.Fatalf("Failed to insert split: %v", err) + } + + return orgID, userID, transactionID +} + +func createTestFile(t *testing.T) (string, []byte) { + content := []byte("This is a test file content for attachment testing") + tmpDir := t.TempDir() + filePath := filepath.Join(tmpDir, "test.txt") + + err := os.WriteFile(filePath, content, 0644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + return filePath, content +} + + +func TestAttachmentIntegration(t *testing.T) { + db, cleanup := setupTestDatabase(t) + defer cleanup() + + orgID, userID, transactionID := setupTestData(t, db) + + // Set up the model instance for the API handlers + bc := &util.StandardBcrypt{} + + // Use the existing datastore model which has the attachment implementation + // We need to create it with the database connection + datastoreModel := model.NewModel(nil, bc, types.Config{}) + model.Instance = datastoreModel + + t.Run("Database Integration Test", func(t *testing.T) { + // Test direct database operations first + filePath, originalContent := createTestFile(t) + defer os.Remove(filePath) + + // Create attachment record directly + attachmentID := id.String(id.New()) + uploadTime := time.Now() + + attachment := types.Attachment{ + Id: attachmentID, + TransactionId: transactionID, + OrgId: orgID, + UserId: userID, + FileName: "stored_test.txt", + OriginalName: "test.txt", + ContentType: "text/plain", + FileSize: int64(len(originalContent)), + FilePath: "uploads/test/" + attachmentID + ".txt", + Description: "Test attachment description", + Uploaded: uploadTime, + Deleted: false, + } + + // Insert using the existing model + createdAttachment, err := model.Instance.CreateAttachment(&attachment) + assert.NoError(t, err) + assert.NotNil(t, createdAttachment) + assert.Equal(t, attachmentID, createdAttachment.Id) + + // Verify database persistence + var dbAttachment types.Attachment + err = db.Raw("SELECT HEX(id) as id, HEX(transactionId) as transactionId, HEX(orgId) as orgId, HEX(userId) as userId, fileName, originalName, contentType, fileSize, filePath, description, uploaded, deleted FROM attachment WHERE HEX(id) = ?", attachmentID).Scan(&dbAttachment).Error + assert.NoError(t, err) + + assert.Equal(t, attachmentID, dbAttachment.Id) + assert.Equal(t, transactionID, dbAttachment.TransactionId) + assert.Equal(t, "Test attachment description", dbAttachment.Description) + + // Test retrieval + retrievedAttachment, err := model.Instance.GetAttachment(attachmentID, transactionID, orgID, userID) + assert.NoError(t, err) + assert.NotNil(t, retrievedAttachment) + assert.Equal(t, attachmentID, retrievedAttachment.Id) + + // Test listing by transaction + attachments, err := model.Instance.GetAttachmentsByTransaction(transactionID, orgID, userID) + assert.NoError(t, err) + assert.Len(t, attachments, 1) + assert.Equal(t, attachmentID, attachments[0].Id) + + // Test soft deletion + err = model.Instance.DeleteAttachment(attachmentID, transactionID, orgID, userID) + assert.NoError(t, err) + + // Verify soft deletion in database + var deletedAttachment types.Attachment + err = db.Raw("SELECT deleted FROM attachment WHERE HEX(id) = ?", attachmentID).Scan(&deletedAttachment).Error + assert.NoError(t, err) + assert.True(t, deletedAttachment.Deleted) + + // Verify attachment is no longer accessible + retrievedAttachment, err = model.Instance.GetAttachment(attachmentID, transactionID, orgID, userID) + assert.Error(t, err) + assert.Nil(t, retrievedAttachment) + }) + + t.Run("File Upload Integration Test", func(t *testing.T) { + // Test file upload functionality + filePath, originalContent := createTestFile(t) + defer os.Remove(filePath) + + // Create upload directory + uploadDir := "uploads/test" + os.MkdirAll(uploadDir, 0755) + defer os.RemoveAll("uploads") + + // Simulate file upload process + attachmentID := id.String(id.New()) + storedFilePath := filepath.Join(uploadDir, attachmentID+".txt") + + // Copy file to upload location + err := copyFile(filePath, storedFilePath) + assert.NoError(t, err) + + // Create attachment record + attachment := types.Attachment{ + Id: attachmentID, + TransactionId: transactionID, + OrgId: orgID, + UserId: userID, + FileName: filepath.Base(storedFilePath), + OriginalName: "test.txt", + ContentType: "text/plain", + FileSize: int64(len(originalContent)), + FilePath: storedFilePath, + Description: "Uploaded test file", + Uploaded: time.Now(), + Deleted: false, + } + + createdAttachment, err := model.Instance.CreateAttachment(&attachment) + assert.NoError(t, err) + assert.NotNil(t, createdAttachment) + + // Verify file exists + _, err = os.Stat(storedFilePath) + assert.NoError(t, err) + + // Verify database record + retrievedAttachment, err := model.Instance.GetAttachment(attachmentID, transactionID, orgID, userID) + assert.NoError(t, err) + assert.Equal(t, storedFilePath, retrievedAttachment.FilePath) + assert.Equal(t, int64(len(originalContent)), retrievedAttachment.FileSize) + }) +} + +// Helper function to copy files +func copyFile(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.Create(dst) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + return err +} + +func TestAttachmentValidation(t *testing.T) { + db, cleanup := setupTestDatabase(t) + defer cleanup() + + orgID, userID, transactionID := setupTestData(t, db) + + // Set up the model instance + bc := &util.StandardBcrypt{} + gormModel := model.NewGormModel(db, bc, types.Config{}) + model.Instance = gormModel + + t.Run("Invalid attachment data", func(t *testing.T) { + // Test with missing required fields + attachment := types.Attachment{ + // Missing ID + TransactionId: transactionID, + OrgId: orgID, + UserId: userID, + } + + createdAttachment, err := model.Instance.CreateAttachment(&attachment) + assert.Error(t, err) + assert.Nil(t, createdAttachment) + }) + + t.Run("Non-existent attachment retrieval", func(t *testing.T) { + nonExistentID := id.String(id.New()) + + attachment, err := model.Instance.GetAttachment(nonExistentID, transactionID, orgID, userID) + assert.Error(t, err) + assert.Nil(t, attachment) + }) +} \ No newline at end of file diff --git a/core/api/attachment_storage.go b/core/api/attachment_storage.go new file mode 100644 index 0000000..f3ddea8 --- /dev/null +++ b/core/api/attachment_storage.go @@ -0,0 +1,289 @@ +package api + +import ( + "fmt" + "io" + "mime/multipart" + "net/http" + "time" + + "github.com/ant0ine/go-json-rest/rest" + "github.com/openaccounting/oa-server/core/model" + "github.com/openaccounting/oa-server/core/model/types" + "github.com/openaccounting/oa-server/core/storage" + "github.com/openaccounting/oa-server/core/util" + "github.com/openaccounting/oa-server/core/util/id" +) + +// AttachmentHandler handles attachment operations with configurable storage +type AttachmentHandler struct { + storage storage.Storage +} + +// Global attachment handler instance (will be initialized during server startup) +var attachmentHandler *AttachmentHandler + +// InitializeAttachmentHandler initializes the global attachment handler with storage backend +func InitializeAttachmentHandler(storageConfig storage.Config) error { + storageBackend, err := storage.NewStorage(storageConfig) + if err != nil { + return fmt.Errorf("failed to initialize storage backend: %w", err) + } + + attachmentHandler = &AttachmentHandler{ + storage: storageBackend, + } + + return nil +} + +// PostAttachmentWithStorage handles file upload using the configured storage backend +func PostAttachmentWithStorage(w rest.ResponseWriter, r *rest.Request) { + if attachmentHandler == nil { + rest.Error(w, "Storage backend not initialized", http.StatusInternalServerError) + return + } + + transactionId := r.FormValue("transactionId") + if transactionId == "" { + rest.Error(w, "Transaction ID is required", http.StatusBadRequest) + return + } + + if !util.IsValidUUID(transactionId) { + rest.Error(w, "Invalid transaction ID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + // Parse multipart form + err := r.ParseMultipartForm(MaxFileSize) + if err != nil { + rest.Error(w, "Failed to parse multipart form", http.StatusBadRequest) + return + } + + files := r.MultipartForm.File["file"] + if len(files) == 0 { + rest.Error(w, "No file provided", http.StatusBadRequest) + return + } + + fileHeader := files[0] // Take the first file + + // Verify transaction exists and user has permission + tx, err := model.Instance.GetTransaction(transactionId, "", user.Id) + if err != nil { + rest.Error(w, "Transaction not found", http.StatusNotFound) + return + } + if tx == nil { + rest.Error(w, "Transaction not found", http.StatusNotFound) + return + } + + // Process the file upload + attachment, err := attachmentHandler.processFileUploadWithStorage(fileHeader, transactionId, tx.OrgId, user.Id, r.FormValue("description")) + if err != nil { + rest.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Save attachment to database + createdAttachment, err := model.Instance.CreateAttachment(attachment) + if err != nil { + // Clean up the stored file on database error + attachmentHandler.storage.Delete(attachment.FilePath) + rest.Error(w, "Failed to save attachment", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusCreated) + w.WriteJson(createdAttachment) +} + +// GetAttachmentWithStorage retrieves an attachment using the configured storage backend +func GetAttachmentWithStorage(w rest.ResponseWriter, r *rest.Request) { + if attachmentHandler == nil { + rest.Error(w, "Storage backend not initialized", http.StatusInternalServerError) + return + } + + attachmentId := r.PathParam("id") + if !util.IsValidUUID(attachmentId) { + rest.Error(w, "Invalid attachment ID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + // Get attachment from database + attachment, err := model.Instance.GetAttachment(attachmentId, "", "", user.Id) + if err != nil { + rest.Error(w, "Attachment not found", http.StatusNotFound) + return + } + + // Check if this is a download request + if r.URL.Query().Get("download") == "true" { + // Stream the file directly to the client + err := attachmentHandler.streamFile(w, attachment) + if err != nil { + rest.Error(w, "Failed to retrieve file", http.StatusInternalServerError) + return + } + return + } + + // Return attachment metadata + w.WriteJson(attachment) +} + +// GetAttachmentDownloadURL returns a download URL for an attachment +func GetAttachmentDownloadURL(w rest.ResponseWriter, r *rest.Request) { + if attachmentHandler == nil { + rest.Error(w, "Storage backend not initialized", http.StatusInternalServerError) + return + } + + attachmentId := r.PathParam("id") + if !util.IsValidUUID(attachmentId) { + rest.Error(w, "Invalid attachment ID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + // Get attachment from database + attachment, err := model.Instance.GetAttachment(attachmentId, "", "", user.Id) + if err != nil { + rest.Error(w, "Attachment not found", http.StatusNotFound) + return + } + + // Generate download URL (valid for 1 hour) + url, err := attachmentHandler.storage.GetURL(attachment.FilePath, time.Hour) + if err != nil { + rest.Error(w, "Failed to generate download URL", http.StatusInternalServerError) + return + } + + response := map[string]string{ + "url": url, + "expiresIn": "3600", // 1 hour in seconds + } + + w.WriteJson(response) +} + +// DeleteAttachmentWithStorage deletes an attachment using the configured storage backend +func DeleteAttachmentWithStorage(w rest.ResponseWriter, r *rest.Request) { + if attachmentHandler == nil { + rest.Error(w, "Storage backend not initialized", http.StatusInternalServerError) + return + } + + attachmentId := r.PathParam("id") + if !util.IsValidUUID(attachmentId) { + rest.Error(w, "Invalid attachment ID format", http.StatusBadRequest) + return + } + + user := r.Env["USER"].(*types.User) + + // Get attachment from database first + attachment, err := model.Instance.GetAttachment(attachmentId, "", "", user.Id) + if err != nil { + rest.Error(w, "Attachment not found", http.StatusNotFound) + return + } + + // Delete from database (soft delete) + err = model.Instance.DeleteAttachment(attachmentId, attachment.TransactionId, attachment.OrgId, user.Id) + if err != nil { + rest.Error(w, "Failed to delete attachment", http.StatusInternalServerError) + return + } + + // Delete from storage backend + // Note: For production, you might want to delay physical deletion + // and run a cleanup job later to handle any issues + err = attachmentHandler.storage.Delete(attachment.FilePath) + if err != nil { + // Log the error but don't fail the request since database deletion succeeded + // The file can be cleaned up later by a maintenance job + fmt.Printf("Warning: Failed to delete file from storage: %v\n", err) + } + + w.WriteHeader(http.StatusOK) + w.WriteJson(map[string]string{"status": "deleted"}) +} + +// processFileUploadWithStorage processes a file upload using the storage backend +func (h *AttachmentHandler) processFileUploadWithStorage(fileHeader *multipart.FileHeader, transactionId, orgId, userId, description string) (*types.Attachment, error) { + // Validate file size + if fileHeader.Size > MaxFileSize { + return nil, fmt.Errorf("file too large. Maximum size is %d bytes", MaxFileSize) + } + + // Validate content type + contentType := fileHeader.Header.Get("Content-Type") + if !AllowedMimeTypes[contentType] { + return nil, fmt.Errorf("unsupported file type: %s", contentType) + } + + // Open the file + file, err := fileHeader.Open() + if err != nil { + return nil, fmt.Errorf("failed to open uploaded file: %w", err) + } + defer file.Close() + + // Store the file using the storage backend + storagePath, err := h.storage.Store(fileHeader.Filename, file, contentType) + if err != nil { + return nil, fmt.Errorf("failed to store file: %w", err) + } + + // Create attachment record + attachment := &types.Attachment{ + Id: id.String(id.New()), + TransactionId: transactionId, + OrgId: orgId, + UserId: userId, + FileName: storagePath, // Store the storage path/key + OriginalName: fileHeader.Filename, + ContentType: contentType, + FileSize: fileHeader.Size, + FilePath: storagePath, // For backward compatibility + Description: description, + Uploaded: time.Now(), + Deleted: false, + } + + return attachment, nil +} + +// streamFile streams a file from storage to the HTTP response +func (h *AttachmentHandler) streamFile(w rest.ResponseWriter, attachment *types.Attachment) error { + // Get file from storage + reader, err := h.storage.Retrieve(attachment.FilePath) + if err != nil { + return fmt.Errorf("failed to retrieve file: %w", err) + } + defer reader.Close() + + // Set appropriate headers + w.Header().Set("Content-Type", attachment.ContentType) + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", attachment.OriginalName)) + + // If we know the file size, set Content-Length + if attachment.FileSize > 0 { + w.Header().Set("Content-Length", fmt.Sprintf("%d", attachment.FileSize)) + } + + // Stream the file to the client + _, err = io.Copy(w.(http.ResponseWriter), reader) + return err +} \ No newline at end of file diff --git a/core/api/routes.go b/core/api/routes.go index 648b69b..9f97c26 100644 --- a/core/api/routes.go +++ b/core/api/routes.go @@ -31,6 +31,17 @@ func GetRouter(auth *AuthMiddleware, prefix string) (rest.App, error) { rest.Post(prefix+"/orgs/:orgId/transactions", auth.RequireAuth(PostTransaction)), rest.Put(prefix+"/orgs/:orgId/transactions/:transactionId", auth.RequireAuth(PutTransaction)), rest.Delete(prefix+"/orgs/:orgId/transactions/:transactionId", auth.RequireAuth(DeleteTransaction)), + rest.Get(prefix+"/orgs/:orgId/transactions/:transactionId/attachments", auth.RequireAuth(GetAttachments)), + rest.Post(prefix+"/orgs/:orgId/transactions/:transactionId/attachments", auth.RequireAuth(PostAttachment)), + rest.Get(prefix+"/orgs/:orgId/transactions/:transactionId/attachments/:attachmentId", auth.RequireAuth(GetAttachment)), + rest.Get(prefix+"/orgs/:orgId/transactions/:transactionId/attachments/:attachmentId/download", auth.RequireAuth(DownloadAttachment)), + rest.Delete(prefix+"/orgs/:orgId/transactions/:transactionId/attachments/:attachmentId", auth.RequireAuth(DeleteAttachment)), + + // New storage-based attachment endpoints + rest.Post(prefix+"/attachments", auth.RequireAuth(PostAttachmentWithStorage)), + rest.Get(prefix+"/attachments/:id", auth.RequireAuth(GetAttachmentWithStorage)), + rest.Get(prefix+"/attachments/:id/url", auth.RequireAuth(GetAttachmentDownloadURL)), + rest.Delete(prefix+"/attachments/:id", auth.RequireAuth(DeleteAttachmentWithStorage)), rest.Get(prefix+"/orgs/:orgId/prices", auth.RequireAuth(GetPrices)), rest.Post(prefix+"/orgs/:orgId/prices", auth.RequireAuth(PostPrice)), rest.Delete(prefix+"/orgs/:orgId/prices/:priceId", auth.RequireAuth(DeletePrice)), diff --git a/core/mocks/Datastore.go b/core/mocks/Datastore.go index e494d81..dccd686 100644 --- a/core/mocks/Datastore.go +++ b/core/mocks/Datastore.go @@ -993,3 +993,74 @@ func (_m *Datastore) VerifyUser(_a0 string) error { return r0 } + +// Attachment interface mock methods +func (_m *Datastore) InsertAttachment(_a0 *types.Attachment) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(*types.Attachment) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +func (_m *Datastore) GetAttachment(_a0 string, _a1 string, _a2 string) (*types.Attachment, error) { + ret := _m.Called(_a0, _a1, _a2) + + var r0 *types.Attachment + if rf, ok := ret.Get(0).(func(string, string, string) *types.Attachment); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Attachment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +func (_m *Datastore) GetAttachmentsByTransaction(_a0 string, _a1 string) ([]*types.Attachment, error) { + ret := _m.Called(_a0, _a1) + + var r0 []*types.Attachment + if rf, ok := ret.Get(0).(func(string, string) []*types.Attachment); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Attachment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +func (_m *Datastore) DeleteAttachment(_a0 string, _a1 string, _a2 string) error { + ret := _m.Called(_a0, _a1, _a2) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, string) error); ok { + r0 = rf(_a0, _a1, _a2) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/core/model/account.go b/core/model/account.go index a2dd94d..d4ecec7 100644 --- a/core/model/account.go +++ b/core/model/account.go @@ -408,6 +408,15 @@ func (model *Model) accountsContainWriteAccess(accounts []*types.Account, accoun return false } +func (model *Model) accountsContainReadAccess(accounts []*types.Account, accountId string) bool { + for _, account := range accounts { + if account.Id == accountId { + return true + } + } + return false +} + func (model *Model) getAccountFromList(accounts []*types.Account, accountId string) *types.Account { for _, account := range accounts { if account.Id == accountId { diff --git a/core/model/account_test.go b/core/model/account_test.go index 32fb972..0b3872b 100644 --- a/core/model/account_test.go +++ b/core/model/account_test.go @@ -162,6 +162,10 @@ func TestCreateAccount(t *testing.T) { td := &TdAccount{} td.On("GetAccountsByOrgId", "1").Return(getTestAccounts(), nil) + // Mock GetSplitCountByAccountId for parent account check + if test.account.Parent != "" { + td.On("GetSplitCountByAccountId", test.account.Parent).Return(int64(0), nil) + } model := NewModel(td, nil, types.Config{}) @@ -206,6 +210,10 @@ func TestUpdateAccount(t *testing.T) { td := &TdAccount{} td.On("GetAccountsByOrgId", "1").Return(getTestAccounts(), nil) + // Mock GetSplitCountByAccountId for parent account check + if test.account.Parent != "" { + td.On("GetSplitCountByAccountId", test.account.Parent).Return(int64(0), nil) + } model := NewModel(td, nil, types.Config{}) diff --git a/core/model/attachment.go b/core/model/attachment.go new file mode 100644 index 0000000..01af3f1 --- /dev/null +++ b/core/model/attachment.go @@ -0,0 +1,163 @@ +package model + +import ( + "errors" + "time" + + "github.com/openaccounting/oa-server/core/model/types" +) + +type AttachmentInterface interface { + CreateAttachment(*types.Attachment) (*types.Attachment, error) + GetAttachmentsByTransaction(string, string, string) ([]*types.Attachment, error) + GetAttachment(string, string, string, string) (*types.Attachment, error) + DeleteAttachment(string, string, string, string) error +} + +func (model *Model) CreateAttachment(attachment *types.Attachment) (*types.Attachment, error) { + if attachment.Id == "" { + return nil, errors.New("attachment ID required") + } + + if attachment.TransactionId == "" { + return nil, errors.New("transaction ID required") + } + + if attachment.OrgId == "" { + return nil, errors.New("organization ID required") + } + + if attachment.UserId == "" { + return nil, errors.New("user ID required") + } + + if attachment.FileName == "" { + return nil, errors.New("file name required") + } + + if attachment.FilePath == "" { + return nil, errors.New("file path required") + } + + // Set upload timestamp + attachment.Uploaded = time.Now() + attachment.Deleted = false + + // Save to database + err := model.db.InsertAttachment(attachment) + if err != nil { + return nil, err + } + + return attachment, nil +} + +func (model *Model) GetAttachmentsByTransaction(transactionId, orgId, userId string) ([]*types.Attachment, error) { + if transactionId == "" { + return nil, errors.New("transaction ID required") + } + + if orgId == "" { + return nil, errors.New("organization ID required") + } + + if userId == "" { + return nil, errors.New("user ID required") + } + + // First verify the user has access to the transaction + tx, err := model.GetTransaction(transactionId, orgId, userId) + if err != nil { + return nil, err + } + if tx == nil { + return nil, errors.New("transaction not found or access denied") + } + + // Get attachments for the transaction + attachments, err := model.db.GetAttachmentsByTransaction(transactionId, orgId) + if err != nil { + return nil, err + } + + return attachments, nil +} + +func (model *Model) GetAttachment(attachmentId, transactionId, orgId, userId string) (*types.Attachment, error) { + if attachmentId == "" { + return nil, errors.New("attachment ID required") + } + + if transactionId == "" { + return nil, errors.New("transaction ID required") + } + + if orgId == "" { + return nil, errors.New("organization ID required") + } + + if userId == "" { + return nil, errors.New("user ID required") + } + + // First verify the user has access to the transaction + tx, err := model.GetTransaction(transactionId, orgId, userId) + if err != nil { + return nil, err + } + if tx == nil { + return nil, errors.New("transaction not found or access denied") + } + + // Get the attachment + attachment, err := model.db.GetAttachment(attachmentId, transactionId, orgId) + if err != nil { + return nil, err + } + + return attachment, nil +} + +func (model *Model) DeleteAttachment(attachmentId, transactionId, orgId, userId string) error { + if attachmentId == "" { + return errors.New("attachment ID required") + } + + if transactionId == "" { + return errors.New("transaction ID required") + } + + if orgId == "" { + return errors.New("organization ID required") + } + + if userId == "" { + return errors.New("user ID required") + } + + // First verify the user has access to the transaction + tx, err := model.GetTransaction(transactionId, orgId, userId) + if err != nil { + return err + } + if tx == nil { + return errors.New("transaction not found or access denied") + } + + // Verify the attachment exists and belongs to the transaction + attachment, err := model.db.GetAttachment(attachmentId, transactionId, orgId) + if err != nil { + return err + } + if attachment == nil { + return errors.New("attachment not found") + } + + // Soft delete the attachment + err = model.db.DeleteAttachment(attachmentId, transactionId, orgId) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/core/model/db/attachment.go b/core/model/db/attachment.go new file mode 100644 index 0000000..7854251 --- /dev/null +++ b/core/model/db/attachment.go @@ -0,0 +1,126 @@ +package db + +import ( + "database/sql" + + "github.com/openaccounting/oa-server/core/model/types" + "github.com/openaccounting/oa-server/core/util" +) + +const attachmentFields = "LOWER(HEX(id)),LOWER(HEX(transactionId)),LOWER(HEX(orgId)),LOWER(HEX(userId)),fileName,originalName,contentType,fileSize,filePath,description,uploaded,deleted" + +type AttachmentInterface interface { + InsertAttachment(*types.Attachment) error + GetAttachment(string, string, string) (*types.Attachment, error) + GetAttachmentsByTransaction(string, string) ([]*types.Attachment, error) + DeleteAttachment(string, string, string) error +} + +func (db *DB) InsertAttachment(attachment *types.Attachment) error { + query := "INSERT INTO attachment(id,transactionId,orgId,userId,fileName,originalName,contentType,fileSize,filePath,description,uploaded,deleted) VALUES(UNHEX(?),UNHEX(?),UNHEX(?),UNHEX(?),?,?,?,?,?,?,?,?)" + + _, err := db.Exec( + query, + attachment.Id, + attachment.TransactionId, + attachment.OrgId, + attachment.UserId, + attachment.FileName, + attachment.OriginalName, + attachment.ContentType, + attachment.FileSize, + attachment.FilePath, + attachment.Description, + util.TimeToMs(attachment.Uploaded), + attachment.Deleted, + ) + + return err +} + +func (db *DB) GetAttachment(attachmentId, transactionId, orgId string) (*types.Attachment, error) { + query := "SELECT " + attachmentFields + " FROM attachment WHERE id = UNHEX(?) AND transactionId = UNHEX(?) AND orgId = UNHEX(?) AND deleted = false" + row := db.QueryRow(query, attachmentId, transactionId, orgId) + + return db.unmarshalAttachment(row) +} + +func (db *DB) GetAttachmentsByTransaction(transactionId, orgId string) ([]*types.Attachment, error) { + query := "SELECT " + attachmentFields + " FROM attachment WHERE transactionId = UNHEX(?) AND orgId = UNHEX(?) AND deleted = false ORDER BY uploaded DESC" + rows, err := db.Query(query, transactionId, orgId) + + if err != nil { + return nil, err + } + + return db.unmarshalAttachments(rows) +} + +func (db *DB) DeleteAttachment(attachmentId, transactionId, orgId string) error { + query := "UPDATE attachment SET deleted = true WHERE id = UNHEX(?) AND transactionId = UNHEX(?) AND orgId = UNHEX(?)" + _, err := db.Exec(query, attachmentId, transactionId, orgId) + return err +} + +func (db *DB) unmarshalAttachment(row *sql.Row) (*types.Attachment, error) { + attachment := &types.Attachment{} + var uploaded int64 + + err := row.Scan( + &attachment.Id, + &attachment.TransactionId, + &attachment.OrgId, + &attachment.UserId, + &attachment.FileName, + &attachment.OriginalName, + &attachment.ContentType, + &attachment.FileSize, + &attachment.FilePath, + &attachment.Description, + &uploaded, + &attachment.Deleted, + ) + + if err != nil { + return nil, err + } + + attachment.Uploaded = util.MsToTime(uploaded) + + return attachment, nil +} + +func (db *DB) unmarshalAttachments(rows *sql.Rows) ([]*types.Attachment, error) { + defer rows.Close() + + attachments := []*types.Attachment{} + + for rows.Next() { + attachment := &types.Attachment{} + var uploaded int64 + + err := rows.Scan( + &attachment.Id, + &attachment.TransactionId, + &attachment.OrgId, + &attachment.UserId, + &attachment.FileName, + &attachment.OriginalName, + &attachment.ContentType, + &attachment.FileSize, + &attachment.FilePath, + &attachment.Description, + &uploaded, + &attachment.Deleted, + ) + + if err != nil { + return nil, err + } + + attachment.Uploaded = util.MsToTime(uploaded) + attachments = append(attachments, attachment) + } + + return attachments, nil +} \ No newline at end of file diff --git a/core/model/db/db.go b/core/model/db/db.go index 5bf638a..b0e2ddd 100644 --- a/core/model/db/db.go +++ b/core/model/db/db.go @@ -15,6 +15,7 @@ type Datastore interface { OrgInterface AccountInterface TransactionInterface + AttachmentInterface PriceInterface SessionInterface ApiKeyInterface diff --git a/core/model/gorm_model.go b/core/model/gorm_model.go index 7cc52cc..fbdcd59 100644 --- a/core/model/gorm_model.go +++ b/core/model/gorm_model.go @@ -247,6 +247,38 @@ func (m *GormModel) InsertTransaction(transaction *types.Transaction) error { return m.repository.InsertTransaction(transaction) } +func (m *GormModel) GetTransaction(transactionId, orgId, userId string) (*types.Transaction, error) { + // For now, delegate to repository - in a full implementation, this would include permission checking + return m.repository.GetTransactionById(transactionId) +} + +// AttachmentInterface implementation +func (m *GormModel) CreateAttachment(attachment *types.Attachment) (*types.Attachment, error) { + if attachment.Id == "" { + return nil, errors.New("attachment ID required") + } + + // Set upload timestamp + attachment.Uploaded = time.Now() + attachment.Deleted = false + + // For GORM implementation, we'd need to implement repository methods + // For now, return an error indicating not implemented + return nil, errors.New("attachment operations not yet implemented for GORM model") +} + +func (m *GormModel) GetAttachmentsByTransaction(transactionId, orgId, userId string) ([]*types.Attachment, error) { + return nil, errors.New("attachment operations not yet implemented for GORM model") +} + +func (m *GormModel) GetAttachment(attachmentId, transactionId, orgId, userId string) (*types.Attachment, error) { + return nil, errors.New("attachment operations not yet implemented for GORM model") +} + +func (m *GormModel) DeleteAttachment(attachmentId, transactionId, orgId, userId string) error { + return errors.New("attachment operations not yet implemented for GORM model") +} + func (m *GormModel) GetTransactionById(id string) (*types.Transaction, error) { return m.repository.GetTransactionById(id) } diff --git a/core/model/model.go b/core/model/model.go index 48e4e8a..10235de 100644 --- a/core/model/model.go +++ b/core/model/model.go @@ -20,11 +20,13 @@ type Interface interface { OrgInterface AccountInterface TransactionInterface + AttachmentInterface PriceInterface SessionInterface ApiKeyInterface SystemHealthInteface BudgetInterface + GetTransaction(string, string, string) (*types.Transaction, error) } func NewModel(db db.Datastore, bcrypt util.Bcrypt, config types.Config) *Model { diff --git a/core/model/transaction.go b/core/model/transaction.go index 87efb60..4d78bca 100644 --- a/core/model/transaction.go +++ b/core/model/transaction.go @@ -169,6 +169,31 @@ func (model *Model) getTransactionById(id string) (*types.Transaction, error) { return model.db.GetTransactionById(id) } +func (model *Model) GetTransaction(transactionId, orgId, userId string) (*types.Transaction, error) { + transaction, err := model.getTransactionById(transactionId) + if err != nil { + return nil, err + } + + if transaction == nil || transaction.OrgId != orgId { + return nil, nil + } + + // Check if user has access to all accounts in the transaction + userAccounts, err := model.GetAccounts(orgId, userId, "") + if err != nil { + return nil, err + } + + for _, split := range transaction.Splits { + if !model.accountsContainReadAccess(userAccounts, split.AccountId) { + return nil, fmt.Errorf("user does not have permission to access account %s", split.AccountId) + } + } + + return transaction, nil +} + func (model *Model) checkSplits(transaction *types.Transaction) (err error) { if len(transaction.Splits) < 2 { return errors.New("at least 2 splits are required") diff --git a/core/model/types/attachment.go b/core/model/types/attachment.go new file mode 100644 index 0000000..7f9c372 --- /dev/null +++ b/core/model/types/attachment.go @@ -0,0 +1,20 @@ +package types + +import ( + "time" +) + +type Attachment struct { + Id string `json:"id"` + TransactionId string `json:"transactionId"` + OrgId string `json:"orgId"` + UserId string `json:"userId"` + FileName string `json:"fileName"` + OriginalName string `json:"originalName"` + ContentType string `json:"contentType"` + FileSize int64 `json:"fileSize"` + FilePath string `json:"filePath"` + Description string `json:"description"` + Uploaded time.Time `json:"uploaded"` + Deleted bool `json:"deleted"` +} \ No newline at end of file diff --git a/core/model/types/config.go b/core/model/types/config.go index f6b98fb..0fbe4b8 100644 --- a/core/model/types/config.go +++ b/core/model/types/config.go @@ -1,5 +1,7 @@ package types +import "github.com/openaccounting/oa-server/core/storage" + type Config struct { WebUrl string `mapstructure:"weburl"` Address string `mapstructure:"address"` @@ -15,8 +17,11 @@ type Config struct { Password string `mapstructure:"password"` // Sensitive: use OA_PASSWORD env var // SQLite specific DatabaseFile string `mapstructure:"databasefile"` + // Email configuration MailgunDomain string `mapstructure:"mailgundomain"` MailgunKey string `mapstructure:"mailgunkey"` // Sensitive: use OA_MAILGUN_KEY env var MailgunEmail string `mapstructure:"mailgunemail"` MailgunSender string `mapstructure:"mailgunsender"` + // Storage configuration + Storage storage.Config `mapstructure:"storage"` } diff --git a/core/server.go b/core/server.go index f79d601..8fa7856 100644 --- a/core/server.go +++ b/core/server.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "strconv" + "strings" "github.com/openaccounting/oa-server/core/api" "github.com/openaccounting/oa-server/core/auth" @@ -31,6 +32,22 @@ func main() { viper.AutomaticEnv() viper.SetEnvPrefix("OA") // will look for OA_DATABASE_PASSWORD, etc. + // Configure Viper to handle nested config with environment variables + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + // Bind specific storage environment variables for better support + // Using mapstructure field names (snake_case) + viper.BindEnv("Storage.backend", "OA_STORAGE_BACKEND") + viper.BindEnv("Storage.local.root_dir", "OA_STORAGE_LOCAL_ROOTDIR") + viper.BindEnv("Storage.local.base_url", "OA_STORAGE_LOCAL_BASEURL") + viper.BindEnv("Storage.s3.region", "OA_STORAGE_S3_REGION") + viper.BindEnv("Storage.s3.bucket", "OA_STORAGE_S3_BUCKET") + viper.BindEnv("Storage.s3.prefix", "OA_STORAGE_S3_PREFIX") + viper.BindEnv("Storage.s3.access_key_id", "OA_STORAGE_S3_ACCESSKEYID") + viper.BindEnv("Storage.s3.secret_access_key", "OA_STORAGE_S3_SECRETACCESSKEY") + viper.BindEnv("Storage.s3.endpoint", "OA_STORAGE_S3_ENDPOINT") + viper.BindEnv("Storage.s3.path_style", "OA_STORAGE_S3_PATHSTYLE") + // Set default values viper.SetDefault("Address", "localhost") viper.SetDefault("Port", 8080) @@ -38,6 +55,11 @@ func main() { viper.SetDefault("DatabaseFile", "./openaccounting.db") viper.SetDefault("ApiPrefix", "/api/v1") + // Set storage defaults (using mapstructure field names) + viper.SetDefault("Storage.backend", "local") + viper.SetDefault("Storage.local.root_dir", "./uploads") + viper.SetDefault("Storage.local.base_url", "") + // Read configuration err := viper.ReadInConfig() if err != nil { @@ -50,6 +72,14 @@ func main() { if err != nil { log.Fatal(fmt.Errorf("failed to unmarshal config: %s", err.Error())) } + + // Set storage defaults if not configured (Viper doesn't handle nested defaults well) + if config.Storage.Backend == "" { + config.Storage.Backend = "local" + } + if config.Storage.Local.RootDir == "" { + config.Storage.Local.RootDir = "./uploads" + } // Parse database address (assuming format host:port for MySQL) host := config.DatabaseAddress @@ -105,6 +135,12 @@ func main() { // Set the global model instance model.Instance = gormModel + // Initialize storage backend for attachments + err = api.InitializeAttachmentHandler(config.Storage) + if err != nil { + log.Fatal(fmt.Errorf("failed to initialize storage backend: %s", err.Error())) + } + app, err := api.Init(config.ApiPrefix) if err != nil { log.Fatal(fmt.Errorf("failed to create api instance with: %s", err.Error())) diff --git a/core/storage/interface.go b/core/storage/interface.go new file mode 100644 index 0000000..ed7c9df --- /dev/null +++ b/core/storage/interface.go @@ -0,0 +1,106 @@ +package storage + +import ( + "io" + "time" +) + +// Storage defines the interface for file storage backends +type Storage interface { + // Store saves a file and returns the storage path/key + Store(filename string, content io.Reader, contentType string) (string, error) + + // Retrieve gets a file by its storage path/key + Retrieve(path string) (io.ReadCloser, error) + + // Delete removes a file by its storage path/key + Delete(path string) error + + // GetURL returns a URL for accessing the file (may be signed/temporary) + GetURL(path string, expiry time.Duration) (string, error) + + // Exists checks if a file exists at the given path + Exists(path string) (bool, error) + + // GetMetadata returns file metadata (size, last modified, etc.) + GetMetadata(path string) (*FileMetadata, error) +} + +// FileMetadata contains information about a stored file +type FileMetadata struct { + Size int64 + LastModified time.Time + ContentType string + ETag string +} + +// Config holds configuration for storage backends +type Config struct { + // Storage backend type: "local", "s3" + Backend string `mapstructure:"backend"` + + // Local filesystem configuration + Local LocalConfig `mapstructure:"local"` + + // S3-compatible storage configuration (S3, B2, R2, etc.) + S3 S3Config `mapstructure:"s3"` +} + +// LocalConfig configures local filesystem storage +type LocalConfig struct { + // Root directory for file storage + RootDir string `mapstructure:"root_dir"` + + // Base URL for serving files (optional) + BaseURL string `mapstructure:"base_url"` +} + +// S3Config configures S3-compatible storage (AWS S3, Backblaze B2, Cloudflare R2, etc.) +type S3Config struct { + // AWS Region (use "auto" for Cloudflare R2) + Region string `mapstructure:"region"` + + // S3 Bucket name + Bucket string `mapstructure:"bucket"` + + // Optional prefix for all objects + Prefix string `mapstructure:"prefix"` + + // Access Key ID + AccessKeyID string `mapstructure:"access_key_id"` + + // Secret Access Key + SecretAccessKey string `mapstructure:"secret_access_key"` + + // Custom endpoint URL for S3-compatible services: + // - Backblaze B2: https://s3.us-west-004.backblazeb2.com + // - Cloudflare R2: https://.r2.cloudflarestorage.com + // - MinIO: http://localhost:9000 + // Leave empty for AWS S3 + Endpoint string `mapstructure:"endpoint"` + + // Use path-style addressing (required for some S3-compatible services) + PathStyle bool `mapstructure:"path_style"` +} + + +// NewStorage creates a new storage backend based on configuration +func NewStorage(config Config) (Storage, error) { + switch config.Backend { + case "local", "": + return NewLocalStorage(config.Local) + case "s3": + return NewS3Storage(config.S3) + default: + return nil, &UnsupportedBackendError{Backend: config.Backend} + } +} + +// UnsupportedBackendError is returned when an unknown storage backend is requested +type UnsupportedBackendError struct { + Backend string +} + +func (e *UnsupportedBackendError) Error() string { + return "unsupported storage backend: " + e.Backend +} \ No newline at end of file diff --git a/core/storage/interface_test.go b/core/storage/interface_test.go new file mode 100644 index 0000000..9edfcd4 --- /dev/null +++ b/core/storage/interface_test.go @@ -0,0 +1,101 @@ +package storage + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewStorage(t *testing.T) { + t.Run("Local Storage", func(t *testing.T) { + config := Config{ + Backend: "local", + Local: LocalConfig{ + RootDir: t.TempDir(), + }, + } + + storage, err := NewStorage(config) + assert.NoError(t, err) + assert.IsType(t, &LocalStorage{}, storage) + }) + + t.Run("Default to Local Storage", func(t *testing.T) { + config := Config{ + // No backend specified + Local: LocalConfig{ + RootDir: t.TempDir(), + }, + } + + storage, err := NewStorage(config) + assert.NoError(t, err) + assert.IsType(t, &LocalStorage{}, storage) + }) + + t.Run("S3 Storage", func(t *testing.T) { + config := Config{ + Backend: "s3", + S3: S3Config{ + Region: "us-east-1", + Bucket: "test-bucket", + }, + } + + // This might succeed if AWS credentials are available via IAM roles or env vars + // Let's just check that we get an S3Storage instance or an error + storage, err := NewStorage(config) + if err != nil { + // If it fails, that's expected in test environments without AWS access + assert.Nil(t, storage) + } else { + // If it succeeds, we should get an S3Storage instance + assert.IsType(t, &S3Storage{}, storage) + } + }) + + t.Run("B2 Storage", func(t *testing.T) { + config := Config{ + Backend: "b2", + B2: B2Config{ + AccountID: "test-account", + ApplicationKey: "test-key", + Bucket: "test-bucket", + }, + } + + // This will fail because we don't have real B2 credentials + storage, err := NewStorage(config) + assert.Error(t, err) // Expected to fail without credentials + assert.Nil(t, storage) + }) + + t.Run("Unsupported Backend", func(t *testing.T) { + config := Config{ + Backend: "unsupported", + } + + storage, err := NewStorage(config) + assert.Error(t, err) + assert.IsType(t, &UnsupportedBackendError{}, err) + assert.Nil(t, storage) + assert.Contains(t, err.Error(), "unsupported") + }) +} + +func TestStorageErrors(t *testing.T) { + t.Run("UnsupportedBackendError", func(t *testing.T) { + err := &UnsupportedBackendError{Backend: "ftp"} + assert.Equal(t, "unsupported storage backend: ftp", err.Error()) + }) + + t.Run("FileNotFoundError", func(t *testing.T) { + err := &FileNotFoundError{Path: "missing.txt"} + assert.Equal(t, "file not found: missing.txt", err.Error()) + }) + + t.Run("InvalidPathError", func(t *testing.T) { + err := &InvalidPathError{Path: "../../../etc/passwd"} + assert.Equal(t, "invalid path: ../../../etc/passwd", err.Error()) + }) +} \ No newline at end of file diff --git a/core/storage/local.go b/core/storage/local.go new file mode 100644 index 0000000..eaade8a --- /dev/null +++ b/core/storage/local.go @@ -0,0 +1,243 @@ +package storage + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + "time" + + "github.com/openaccounting/oa-server/core/util/id" +) + +// LocalStorage implements the Storage interface for local filesystem +type LocalStorage struct { + rootDir string + baseURL string +} + +// NewLocalStorage creates a new local filesystem storage backend +func NewLocalStorage(config LocalConfig) (*LocalStorage, error) { + rootDir := config.RootDir + if rootDir == "" { + rootDir = "./uploads" + } + + // Ensure the root directory exists + if err := os.MkdirAll(rootDir, 0755); err != nil { + return nil, fmt.Errorf("failed to create storage directory: %w", err) + } + + return &LocalStorage{ + rootDir: rootDir, + baseURL: config.BaseURL, + }, nil +} + +// Store saves a file to the local filesystem +func (l *LocalStorage) Store(filename string, content io.Reader, contentType string) (string, error) { + // Generate a unique storage path + storagePath := l.generateStoragePath(filename) + fullPath := filepath.Join(l.rootDir, storagePath) + + // Ensure the directory exists + dir := filepath.Dir(fullPath) + if err := os.MkdirAll(dir, 0755); err != nil { + return "", fmt.Errorf("failed to create directory: %w", err) + } + + // Create and write the file + file, err := os.Create(fullPath) + if err != nil { + return "", fmt.Errorf("failed to create file: %w", err) + } + defer file.Close() + + _, err = io.Copy(file, content) + if err != nil { + // Clean up the file if write failed + os.Remove(fullPath) + return "", fmt.Errorf("failed to write file: %w", err) + } + + return storagePath, nil +} + +// Retrieve gets a file from the local filesystem +func (l *LocalStorage) Retrieve(path string) (io.ReadCloser, error) { + // Validate path to prevent directory traversal + if err := l.validatePath(path); err != nil { + return nil, err + } + + fullPath := filepath.Join(l.rootDir, path) + file, err := os.Open(fullPath) + if err != nil { + if os.IsNotExist(err) { + return nil, &FileNotFoundError{Path: path} + } + return nil, fmt.Errorf("failed to open file: %w", err) + } + + return file, nil +} + +// Delete removes a file from the local filesystem +func (l *LocalStorage) Delete(path string) error { + // Validate path to prevent directory traversal + if err := l.validatePath(path); err != nil { + return err + } + + fullPath := filepath.Join(l.rootDir, path) + err := os.Remove(fullPath) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to delete file: %w", err) + } + + // Try to remove empty parent directories + l.cleanupEmptyDirs(filepath.Dir(fullPath)) + + return nil +} + +// GetURL returns a URL for accessing the file +func (l *LocalStorage) GetURL(path string, expiry time.Duration) (string, error) { + // Validate path to prevent directory traversal + if err := l.validatePath(path); err != nil { + return "", err + } + + // Check if file exists + exists, err := l.Exists(path) + if err != nil { + return "", err + } + if !exists { + return "", &FileNotFoundError{Path: path} + } + + if l.baseURL != "" { + // Return a public URL if base URL is configured + return l.baseURL + "/" + path, nil + } + + // For local storage without a base URL, return the file path + // In a real application, you might serve these through an endpoint + return "/files/" + path, nil +} + +// Exists checks if a file exists at the given path +func (l *LocalStorage) Exists(path string) (bool, error) { + // Validate path to prevent directory traversal + if err := l.validatePath(path); err != nil { + return false, err + } + + fullPath := filepath.Join(l.rootDir, path) + _, err := os.Stat(fullPath) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, fmt.Errorf("failed to check file existence: %w", err) + } + + return true, nil +} + +// GetMetadata returns file metadata +func (l *LocalStorage) GetMetadata(path string) (*FileMetadata, error) { + // Validate path to prevent directory traversal + if err := l.validatePath(path); err != nil { + return nil, err + } + + fullPath := filepath.Join(l.rootDir, path) + info, err := os.Stat(fullPath) + if err != nil { + if os.IsNotExist(err) { + return nil, &FileNotFoundError{Path: path} + } + return nil, fmt.Errorf("failed to get file metadata: %w", err) + } + + return &FileMetadata{ + Size: info.Size(), + LastModified: info.ModTime(), + ContentType: "", // Local storage doesn't store content type + ETag: "", // Local storage doesn't have ETags + }, nil +} + +// generateStoragePath creates a unique storage path for a file +func (l *LocalStorage) generateStoragePath(filename string) string { + // Generate a unique ID for the file + fileID := id.String(id.New()) + + // Extract file extension + ext := filepath.Ext(filename) + + // Create a path structure: YYYY/MM/DD/uuid.ext + now := time.Now() + datePath := fmt.Sprintf("%04d/%02d/%02d", now.Year(), now.Month(), now.Day()) + + return filepath.Join(datePath, fileID+ext) +} + +// validatePath ensures the path doesn't contain directory traversal attempts +func (l *LocalStorage) validatePath(path string) error { + // Clean the path and check for traversal attempts + cleanPath := filepath.Clean(path) + + // Reject paths that try to go up directories + if strings.Contains(cleanPath, "..") { + return &InvalidPathError{Path: path} + } + + // Reject absolute paths + if filepath.IsAbs(cleanPath) { + return &InvalidPathError{Path: path} + } + + return nil +} + +// cleanupEmptyDirs removes empty parent directories up to the root +func (l *LocalStorage) cleanupEmptyDirs(dir string) { + // Don't remove the root directory + if dir == l.rootDir { + return + } + + // Check if directory is empty + entries, err := os.ReadDir(dir) + if err != nil || len(entries) > 0 { + return + } + + // Remove empty directory + if err := os.Remove(dir); err == nil { + // Recursively clean parent directories + l.cleanupEmptyDirs(filepath.Dir(dir)) + } +} + +// FileNotFoundError is returned when a file doesn't exist +type FileNotFoundError struct { + Path string +} + +func (e *FileNotFoundError) Error() string { + return "file not found: " + e.Path +} + +// InvalidPathError is returned when a path is invalid or contains traversal attempts +type InvalidPathError struct { + Path string +} + +func (e *InvalidPathError) Error() string { + return "invalid path: " + e.Path +} \ No newline at end of file diff --git a/core/storage/local_test.go b/core/storage/local_test.go new file mode 100644 index 0000000..4458231 --- /dev/null +++ b/core/storage/local_test.go @@ -0,0 +1,202 @@ +package storage + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestLocalStorage(t *testing.T) { + // Create temporary directory for testing + tmpDir := t.TempDir() + + config := LocalConfig{ + RootDir: tmpDir, + BaseURL: "http://localhost:8080/files", + } + + storage, err := NewLocalStorage(config) + assert.NoError(t, err) + assert.NotNil(t, storage) + + t.Run("Store and Retrieve File", func(t *testing.T) { + content := []byte("test file content") + reader := bytes.NewReader(content) + + // Store file + path, err := storage.Store("test.txt", reader, "text/plain") + assert.NoError(t, err) + assert.NotEmpty(t, path) + + // Verify file exists + exists, err := storage.Exists(path) + assert.NoError(t, err) + assert.True(t, exists) + + // Retrieve file + retrievedReader, err := storage.Retrieve(path) + assert.NoError(t, err) + defer retrievedReader.Close() + + retrievedContent, err := io.ReadAll(retrievedReader) + assert.NoError(t, err) + assert.Equal(t, content, retrievedContent) + }) + + t.Run("Get File Metadata", func(t *testing.T) { + content := []byte("metadata test content") + reader := bytes.NewReader(content) + + path, err := storage.Store("metadata.txt", reader, "text/plain") + assert.NoError(t, err) + + metadata, err := storage.GetMetadata(path) + assert.NoError(t, err) + assert.Equal(t, int64(len(content)), metadata.Size) + assert.False(t, metadata.LastModified.IsZero()) + }) + + t.Run("Get File URL", func(t *testing.T) { + content := []byte("url test content") + reader := bytes.NewReader(content) + + path, err := storage.Store("url.txt", reader, "text/plain") + assert.NoError(t, err) + + url, err := storage.GetURL(path, time.Hour) + assert.NoError(t, err) + assert.Contains(t, url, path) + assert.Contains(t, url, config.BaseURL) + }) + + t.Run("Delete File", func(t *testing.T) { + content := []byte("delete test content") + reader := bytes.NewReader(content) + + path, err := storage.Store("delete.txt", reader, "text/plain") + assert.NoError(t, err) + + // Verify file exists + exists, err := storage.Exists(path) + assert.NoError(t, err) + assert.True(t, exists) + + // Delete file + err = storage.Delete(path) + assert.NoError(t, err) + + // Verify file no longer exists + exists, err = storage.Exists(path) + assert.NoError(t, err) + assert.False(t, exists) + }) + + t.Run("Path Validation", func(t *testing.T) { + // Test directory traversal prevention + _, err := storage.Retrieve("../../../etc/passwd") + assert.Error(t, err) + assert.IsType(t, &InvalidPathError{}, err) + + // Test absolute path rejection + _, err = storage.Retrieve("/etc/passwd") + assert.Error(t, err) + assert.IsType(t, &InvalidPathError{}, err) + }) + + t.Run("File Not Found", func(t *testing.T) { + _, err := storage.Retrieve("nonexistent.txt") + assert.Error(t, err) + assert.IsType(t, &FileNotFoundError{}, err) + + _, err = storage.GetMetadata("nonexistent.txt") + assert.Error(t, err) + assert.IsType(t, &FileNotFoundError{}, err) + + _, err = storage.GetURL("nonexistent.txt", time.Hour) + assert.Error(t, err) + assert.IsType(t, &FileNotFoundError{}, err) + }) + + t.Run("Storage Path Generation", func(t *testing.T) { + content := []byte("path test content") + reader1 := bytes.NewReader(content) + reader2 := bytes.NewReader(content) + + // Store two files with same name + path1, err := storage.Store("same.txt", reader1, "text/plain") + assert.NoError(t, err) + + path2, err := storage.Store("same.txt", reader2, "text/plain") + assert.NoError(t, err) + + // Paths should be different (unique) + assert.NotEqual(t, path1, path2) + + // Both should exist + exists1, err := storage.Exists(path1) + assert.NoError(t, err) + assert.True(t, exists1) + + exists2, err := storage.Exists(path2) + assert.NoError(t, err) + assert.True(t, exists2) + + // Both should have correct extension + assert.True(t, strings.HasSuffix(path1, ".txt")) + assert.True(t, strings.HasSuffix(path2, ".txt")) + + // Should be organized by date + now := time.Now() + expectedPrefix := filepath.Join( + fmt.Sprintf("%04d", now.Year()), + fmt.Sprintf("%02d", now.Month()), + fmt.Sprintf("%02d", now.Day()), + ) + assert.True(t, strings.HasPrefix(path1, expectedPrefix)) + assert.True(t, strings.HasPrefix(path2, expectedPrefix)) + }) +} + +func TestLocalStorageConfig(t *testing.T) { + t.Run("Default Root Directory", func(t *testing.T) { + config := LocalConfig{} // Empty config + + storage, err := NewLocalStorage(config) + assert.NoError(t, err) + assert.NotNil(t, storage) + + // Should create default uploads directory + assert.Equal(t, "./uploads", storage.rootDir) + + // Verify directory was created + _, err = os.Stat("./uploads") + assert.NoError(t, err) + + // Clean up + os.RemoveAll("./uploads") + }) + + t.Run("Custom Root Directory", func(t *testing.T) { + tmpDir := t.TempDir() + customDir := filepath.Join(tmpDir, "custom", "storage") + + config := LocalConfig{ + RootDir: customDir, + } + + storage, err := NewLocalStorage(config) + assert.NoError(t, err) + assert.Equal(t, customDir, storage.rootDir) + + // Verify custom directory was created + _, err = os.Stat(customDir) + assert.NoError(t, err) + }) +} \ No newline at end of file diff --git a/core/storage/s3.go b/core/storage/s3.go new file mode 100644 index 0000000..670d1a9 --- /dev/null +++ b/core/storage/s3.go @@ -0,0 +1,236 @@ +package storage + +import ( + "fmt" + "io" + "path" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/s3/s3manager" + "github.com/openaccounting/oa-server/core/util/id" +) + +// S3Storage implements the Storage interface for Amazon S3 +type S3Storage struct { + client *s3.S3 + uploader *s3manager.Uploader + bucket string + prefix string +} + +// NewS3Storage creates a new S3 storage backend +func NewS3Storage(config S3Config) (*S3Storage, error) { + if config.Bucket == "" { + return nil, fmt.Errorf("S3 bucket name is required") + } + + // Create AWS config + awsConfig := &aws.Config{ + Region: aws.String(config.Region), + } + + // Set custom endpoint if provided (for S3-compatible services) + if config.Endpoint != "" { + awsConfig.Endpoint = aws.String(config.Endpoint) + awsConfig.S3ForcePathStyle = aws.Bool(config.PathStyle) + } + + // Set credentials if provided + if config.AccessKeyID != "" && config.SecretAccessKey != "" { + awsConfig.Credentials = credentials.NewStaticCredentials( + config.AccessKeyID, + config.SecretAccessKey, + "", + ) + } + + // Create session + sess, err := session.NewSession(awsConfig) + if err != nil { + return nil, fmt.Errorf("failed to create AWS session: %w", err) + } + + // Create S3 client + client := s3.New(sess) + uploader := s3manager.NewUploader(sess) + + return &S3Storage{ + client: client, + uploader: uploader, + bucket: config.Bucket, + prefix: config.Prefix, + }, nil +} + +// Store saves a file to S3 +func (s *S3Storage) Store(filename string, content io.Reader, contentType string) (string, error) { + // Generate a unique storage key + storageKey := s.generateStorageKey(filename) + + // Prepare upload input + input := &s3manager.UploadInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(storageKey), + Body: content, + } + + // Set content type if provided + if contentType != "" { + input.ContentType = aws.String(contentType) + } + + // Upload the file + _, err := s.uploader.Upload(input) + if err != nil { + return "", fmt.Errorf("failed to upload file to S3: %w", err) + } + + return storageKey, nil +} + +// Retrieve gets a file from S3 +func (s *S3Storage) Retrieve(path string) (io.ReadCloser, error) { + input := &s3.GetObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(path), + } + + result, err := s.client.GetObject(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case s3.ErrCodeNoSuchKey: + return nil, &FileNotFoundError{Path: path} + } + } + return nil, fmt.Errorf("failed to retrieve file from S3: %w", err) + } + + return result.Body, nil +} + +// Delete removes a file from S3 +func (s *S3Storage) Delete(path string) error { + input := &s3.DeleteObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(path), + } + + _, err := s.client.DeleteObject(input) + if err != nil { + return fmt.Errorf("failed to delete file from S3: %w", err) + } + + return nil +} + +// GetURL returns a presigned URL for accessing the file +func (s *S3Storage) GetURL(path string, expiry time.Duration) (string, error) { + // Check if file exists first + exists, err := s.Exists(path) + if err != nil { + return "", err + } + if !exists { + return "", &FileNotFoundError{Path: path} + } + + // Generate presigned URL + req, _ := s.client.GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(path), + }) + + url, err := req.Presign(expiry) + if err != nil { + return "", fmt.Errorf("failed to generate presigned URL: %w", err) + } + + return url, nil +} + +// Exists checks if a file exists in S3 +func (s *S3Storage) Exists(path string) (bool, error) { + input := &s3.HeadObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(path), + } + + _, err := s.client.HeadObject(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case s3.ErrCodeNoSuchKey, "NotFound": + return false, nil + } + } + return false, fmt.Errorf("failed to check file existence in S3: %w", err) + } + + return true, nil +} + +// GetMetadata returns file metadata from S3 +func (s *S3Storage) GetMetadata(path string) (*FileMetadata, error) { + input := &s3.HeadObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(path), + } + + result, err := s.client.HeadObject(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case s3.ErrCodeNoSuchKey, "NotFound": + return nil, &FileNotFoundError{Path: path} + } + } + return nil, fmt.Errorf("failed to get file metadata from S3: %w", err) + } + + metadata := &FileMetadata{ + Size: aws.Int64Value(result.ContentLength), + } + + if result.LastModified != nil { + metadata.LastModified = *result.LastModified + } + + if result.ContentType != nil { + metadata.ContentType = *result.ContentType + } + + if result.ETag != nil { + metadata.ETag = strings.Trim(*result.ETag, "\"") + } + + return metadata, nil +} + +// generateStorageKey creates a unique storage key for a file +func (s *S3Storage) generateStorageKey(filename string) string { + // Generate a unique ID for the file + fileID := id.String(id.New()) + + // Extract file extension + ext := path.Ext(filename) + + // Create a key structure: prefix/YYYY/MM/DD/uuid.ext + now := time.Now() + datePath := fmt.Sprintf("%04d/%02d/%02d", now.Year(), now.Month(), now.Day()) + + key := path.Join(datePath, fileID+ext) + + // Add prefix if configured + if s.prefix != "" { + key = path.Join(s.prefix, key) + } + + return key +} \ No newline at end of file diff --git a/core/util/util.go b/core/util/util.go index 7ea982e..44cacb8 100644 --- a/core/util/util.go +++ b/core/util/util.go @@ -3,6 +3,7 @@ package util import ( "crypto/rand" "encoding/hex" + "regexp" "time" ) @@ -44,3 +45,23 @@ func NewInviteId() (string, error) { return hex.EncodeToString(byteArray), nil } + +func NewUUID() string { + guid, err := NewGuid() + if err != nil { + // Fallback to timestamp-based UUID if random generation fails + return hex.EncodeToString([]byte(time.Now().Format("20060102150405"))) + } + return guid +} + +func IsValidUUID(uuid string) bool { + // Check if the string is a valid 32-character hex string (16 bytes * 2 hex chars) + if len(uuid) != 32 { + return false + } + + // Check if all characters are valid hex characters + matched, _ := regexp.MatchString("^[0-9a-f]{32}$", uuid) + return matched +} diff --git a/core/ws/ws.go b/core/ws/ws.go index 94ef369..5754de2 100644 --- a/core/ws/ws.go +++ b/core/ws/ws.go @@ -67,7 +67,7 @@ func Handler(w rest.ResponseWriter, r *rest.Request) { continue } - log.Printf("recv: %s", message) + log.Printf("recv: %+v", message) // check version err = checkVersion(message.Version) diff --git a/database/database.go b/database/database.go index 1a9d820..2160094 100644 --- a/database/database.go +++ b/database/database.go @@ -102,6 +102,7 @@ func AutoMigrate() error { &models.APIKey{}, &models.Invite{}, &models.BudgetItem{}, + &models.Attachment{}, ) } @@ -131,6 +132,10 @@ func createIndexes() error { "CREATE INDEX IF NOT EXISTS split_date_index ON splits(date)", "CREATE INDEX IF NOT EXISTS split_updated_index ON splits(updated)", "CREATE INDEX IF NOT EXISTS budgetitem_orgId_index ON budget_items(orgId)", + "CREATE INDEX IF NOT EXISTS attachment_transactionId_index ON attachment(transactionId)", + "CREATE INDEX IF NOT EXISTS attachment_orgId_index ON attachment(orgId)", + "CREATE INDEX IF NOT EXISTS attachment_userId_index ON attachment(userId)", + "CREATE INDEX IF NOT EXISTS attachment_uploaded_index ON attachment(uploaded)", // Additional useful indexes for performance "CREATE INDEX IF NOT EXISTS idx_transaction_date ON transactions(date)", diff --git a/dev.db b/dev.db new file mode 100644 index 0000000..33fa78f Binary files /dev/null and b/dev.db differ diff --git a/go.mod b/go.mod index 319d4ea..c14cf6d 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.2 require ( github.com/Masterminds/semver v0.0.0-20180807142431-c84ddcca87bf github.com/ant0ine/go-json-rest v0.0.0-20170913041208-ebb33769ae01 + github.com/aws/aws-sdk-go v1.44.0 github.com/go-sql-driver/mysql v1.8.1 github.com/gorilla/websocket v0.0.0-20180605202552-5ed622c449da github.com/mailgun/mailgun-go/v4 v4.3.0 @@ -18,6 +19,7 @@ require ( require ( github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect @@ -42,7 +44,7 @@ require ( github.com/json-iterator/go v1.1.10 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect - github.com/pkg/errors v0.8.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/go.sum b/go.sum index 0f8bbe7..b04ccfa 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/Masterminds/semver v0.0.0-20180807142431-c84ddcca87bf h1:BMUJnVJI5J50 github.com/Masterminds/semver v0.0.0-20180807142431-c84ddcca87bf/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/ant0ine/go-json-rest v0.0.0-20170913041208-ebb33769ae01 h1:oYAjCHMjyRaNBo3nUEepDce4LC+Kuh+6jU6y+AllvnU= github.com/ant0ine/go-json-rest v0.0.0-20170913041208-ebb33769ae01/go.mod h1:q6aCt0GfU6LhpBsnZ/2U+mwe+0XB5WStbmwyoPfc+sk= +github.com/aws/aws-sdk-go v1.44.0 h1:jwtHuNqfnJxL4DKHBUVUmQlfueQqBW7oXP6yebZR/R0= +github.com/aws/aws-sdk-go v1.44.0/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -34,6 +36,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -52,8 +58,9 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -84,13 +91,23 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= diff --git a/indexes.sql b/indexes.sql index 3efdcea..c136af0 100644 --- a/indexes.sql +++ b/indexes.sql @@ -3,4 +3,8 @@ CREATE INDEX split_accountId_index ON split (accountId); CREATE INDEX split_transactionId_index ON split (transactionId); CREATE INDEX split_date_index ON split (date); CREATE INDEX split_updated_index ON split (updated); -CREATE INDEX budgetitem_orgId_index ON budgetitem (orgId); \ No newline at end of file +CREATE INDEX budgetitem_orgId_index ON budgetitem (orgId); +CREATE INDEX attachment_transactionId_index ON attachment (transactionId); +CREATE INDEX attachment_orgId_index ON attachment (orgId); +CREATE INDEX attachment_userId_index ON attachment (userId); +CREATE INDEX attachment_uploaded_index ON attachment (uploaded); \ No newline at end of file diff --git a/justfile b/justfile index 017562d..06395b2 100644 --- a/justfile +++ b/justfile @@ -22,7 +22,7 @@ run: build # Run with custom environment run-dev: build @echo "Starting server in development mode..." - OA_DATABASE_DRIVER=sqlite OA_DATABASE_FILE=./dev.db OA_PORT=8080 ./server + OA_DATABASEDRIVER=sqlite OA_DATABASEFILE=./dev.db OA_PORT=8080 ./server # Run tests test: diff --git a/models/attachment.go b/models/attachment.go new file mode 100644 index 0000000..28af0e1 --- /dev/null +++ b/models/attachment.go @@ -0,0 +1,28 @@ +package models + +import ( + "time" +) + +type Attachment struct { + ID []byte `gorm:"type:BINARY(16);primaryKey"` + TransactionID []byte `gorm:"column:transactionId;type:BINARY(16);not null"` + OrgID []byte `gorm:"column:orgId;type:BINARY(16);not null"` + UserID []byte `gorm:"column:userId;type:BINARY(16);not null"` + FileName string `gorm:"column:fileName;size:255;not null"` + OriginalName string `gorm:"column:originalName;size:255;not null"` + ContentType string `gorm:"column:contentType;size:100;not null"` + FileSize int64 `gorm:"column:fileSize;not null"` + FilePath string `gorm:"column:filePath;size:500;not null"` + Description string `gorm:"column:description;size:500"` + Uploaded time.Time `gorm:"column:uploaded;not null"` + Deleted bool `gorm:"column:deleted;default:false"` + + Transaction Transaction `gorm:"foreignKey:TransactionID"` + Org Org `gorm:"foreignKey:OrgID"` + User User `gorm:"foreignKey:UserID"` +} + +func (Attachment) TableName() string { + return "attachment" +} \ No newline at end of file diff --git a/schema.sql b/schema.sql index 6db50e0..7b14628 100644 --- a/schema.sql +++ b/schema.sql @@ -30,4 +30,6 @@ CREATE TABLE apikey (id BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, CREATE TABLE invite (id VARCHAR(32) NOT NULL, orgId BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, updated BIGINT UNSIGNED NOT NULL, email VARCHAR(100) NOT NULL, accepted BOOLEAN NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; -CREATE TABLE budgetitem (id INT UNSIGNED NOT NULL AUTO_INCREMENT, orgId BINARY(16) NOT NULL, accountId BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, amount BIGINT NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; \ No newline at end of file +CREATE TABLE budgetitem (id INT UNSIGNED NOT NULL AUTO_INCREMENT, orgId BINARY(16) NOT NULL, accountId BINARY(16) NOT NULL, inserted BIGINT UNSIGNED NOT NULL, amount BIGINT NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; + +CREATE TABLE attachment (id BINARY(16) NOT NULL, transactionId BINARY(16) NOT NULL, orgId BINARY(16) NOT NULL, userId BINARY(16) NOT NULL, fileName VARCHAR(255) NOT NULL, originalName VARCHAR(255) NOT NULL, contentType VARCHAR(100) NOT NULL, fileSize BIGINT NOT NULL, filePath VARCHAR(500) NOT NULL, description VARCHAR(500), uploaded BIGINT UNSIGNED NOT NULL, deleted BOOLEAN NOT NULL DEFAULT false, PRIMARY KEY(id)) ENGINE=InnoDB; \ No newline at end of file diff --git a/vendor/filippo.io/edwards25519/LICENSE b/vendor/filippo.io/edwards25519/LICENSE deleted file mode 100644 index 6a66aea..0000000 --- a/vendor/filippo.io/edwards25519/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/filippo.io/edwards25519/README.md b/vendor/filippo.io/edwards25519/README.md deleted file mode 100644 index 24e2457..0000000 --- a/vendor/filippo.io/edwards25519/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# filippo.io/edwards25519 - -``` -import "filippo.io/edwards25519" -``` - -This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives. -Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519). - -The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255, and was finally [merged back into the Go standard library](https://golang.org/cl/276272) as of Go 1.17. It now tracks the upstream codebase and extends it with additional functionality. - -Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/internal/edwards25519`/`crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative. - -Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements. diff --git a/vendor/filippo.io/edwards25519/doc.go b/vendor/filippo.io/edwards25519/doc.go deleted file mode 100644 index ab6aaeb..0000000 --- a/vendor/filippo.io/edwards25519/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package edwards25519 implements group logic for the twisted Edwards curve -// -// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2 -// -// This is better known as the Edwards curve equivalent to Curve25519, and is -// the curve used by the Ed25519 signature scheme. -// -// Most users don't need this package, and should instead use crypto/ed25519 for -// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or -// github.com/gtank/ristretto255 for prime order group logic. -// -// However, developers who do need to interact with low-level edwards25519 -// operations can use this package, which is an extended version of -// crypto/internal/edwards25519 from the standard library repackaged as -// an importable module. -package edwards25519 diff --git a/vendor/filippo.io/edwards25519/edwards25519.go b/vendor/filippo.io/edwards25519/edwards25519.go deleted file mode 100644 index a744da2..0000000 --- a/vendor/filippo.io/edwards25519/edwards25519.go +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package edwards25519 - -import ( - "errors" - - "filippo.io/edwards25519/field" -) - -// Point types. - -type projP1xP1 struct { - X, Y, Z, T field.Element -} - -type projP2 struct { - X, Y, Z field.Element -} - -// Point represents a point on the edwards25519 curve. -// -// This type works similarly to math/big.Int, and all arguments and receivers -// are allowed to alias. -// -// The zero value is NOT valid, and it may be used only as a receiver. -type Point struct { - // Make the type not comparable (i.e. used with == or as a map key), as - // equivalent points can be represented by different Go values. - _ incomparable - - // The point is internally represented in extended coordinates (X, Y, Z, T) - // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522. - x, y, z, t field.Element -} - -type incomparable [0]func() - -func checkInitialized(points ...*Point) { - for _, p := range points { - if p.x == (field.Element{}) && p.y == (field.Element{}) { - panic("edwards25519: use of uninitialized Point") - } - } -} - -type projCached struct { - YplusX, YminusX, Z, T2d field.Element -} - -type affineCached struct { - YplusX, YminusX, T2d field.Element -} - -// Constructors. - -func (v *projP2) Zero() *projP2 { - v.X.Zero() - v.Y.One() - v.Z.One() - return v -} - -// identity is the point at infinity. -var identity, _ = new(Point).SetBytes([]byte{ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) - -// NewIdentityPoint returns a new Point set to the identity. -func NewIdentityPoint() *Point { - return new(Point).Set(identity) -} - -// generator is the canonical curve basepoint. See TestGenerator for the -// correspondence of this encoding with the values in RFC 8032. -var generator, _ = new(Point).SetBytes([]byte{ - 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}) - -// NewGeneratorPoint returns a new Point set to the canonical generator. -func NewGeneratorPoint() *Point { - return new(Point).Set(generator) -} - -func (v *projCached) Zero() *projCached { - v.YplusX.One() - v.YminusX.One() - v.Z.One() - v.T2d.Zero() - return v -} - -func (v *affineCached) Zero() *affineCached { - v.YplusX.One() - v.YminusX.One() - v.T2d.Zero() - return v -} - -// Assignments. - -// Set sets v = u, and returns v. -func (v *Point) Set(u *Point) *Point { - *v = *u - return v -} - -// Encoding. - -// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032, -// Section 5.1.2. -func (v *Point) Bytes() []byte { - // This function is outlined to make the allocations inline in the caller - // rather than happen on the heap. - var buf [32]byte - return v.bytes(&buf) -} - -func (v *Point) bytes(buf *[32]byte) []byte { - checkInitialized(v) - - var zInv, x, y field.Element - zInv.Invert(&v.z) // zInv = 1 / Z - x.Multiply(&v.x, &zInv) // x = X / Z - y.Multiply(&v.y, &zInv) // y = Y / Z - - out := copyFieldElement(buf, &y) - out[31] |= byte(x.IsNegative() << 7) - return out -} - -var feOne = new(field.Element).One() - -// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not -// represent a valid point on the curve, SetBytes returns nil and an error and -// the receiver is unchanged. Otherwise, SetBytes returns v. -// -// Note that SetBytes accepts all non-canonical encodings of valid points. -// That is, it follows decoding rules that match most implementations in -// the ecosystem rather than RFC 8032. -func (v *Point) SetBytes(x []byte) (*Point, error) { - // Specifically, the non-canonical encodings that are accepted are - // 1) the ones where the field element is not reduced (see the - // (*field.Element).SetBytes docs) and - // 2) the ones where the x-coordinate is zero and the sign bit is set. - // - // Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am, - // specifically the "Canonical A, R" section. - - y, err := new(field.Element).SetBytes(x) - if err != nil { - return nil, errors.New("edwards25519: invalid point encoding length") - } - - // -x² + y² = 1 + dx²y² - // x² + dx²y² = x²(dy² + 1) = y² - 1 - // x² = (y² - 1) / (dy² + 1) - - // u = y² - 1 - y2 := new(field.Element).Square(y) - u := new(field.Element).Subtract(y2, feOne) - - // v = dy² + 1 - vv := new(field.Element).Multiply(y2, d) - vv = vv.Add(vv, feOne) - - // x = +√(u/v) - xx, wasSquare := new(field.Element).SqrtRatio(u, vv) - if wasSquare == 0 { - return nil, errors.New("edwards25519: invalid point encoding") - } - - // Select the negative square root if the sign bit is set. - xxNeg := new(field.Element).Negate(xx) - xx = xx.Select(xxNeg, xx, int(x[31]>>7)) - - v.x.Set(xx) - v.y.Set(y) - v.z.One() - v.t.Multiply(xx, y) // xy = T / Z - - return v, nil -} - -func copyFieldElement(buf *[32]byte, v *field.Element) []byte { - copy(buf[:], v.Bytes()) - return buf[:] -} - -// Conversions. - -func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 { - v.X.Multiply(&p.X, &p.T) - v.Y.Multiply(&p.Y, &p.Z) - v.Z.Multiply(&p.Z, &p.T) - return v -} - -func (v *projP2) FromP3(p *Point) *projP2 { - v.X.Set(&p.x) - v.Y.Set(&p.y) - v.Z.Set(&p.z) - return v -} - -func (v *Point) fromP1xP1(p *projP1xP1) *Point { - v.x.Multiply(&p.X, &p.T) - v.y.Multiply(&p.Y, &p.Z) - v.z.Multiply(&p.Z, &p.T) - v.t.Multiply(&p.X, &p.Y) - return v -} - -func (v *Point) fromP2(p *projP2) *Point { - v.x.Multiply(&p.X, &p.Z) - v.y.Multiply(&p.Y, &p.Z) - v.z.Square(&p.Z) - v.t.Multiply(&p.X, &p.Y) - return v -} - -// d is a constant in the curve equation. -var d, _ = new(field.Element).SetBytes([]byte{ - 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, - 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, - 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, - 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52}) -var d2 = new(field.Element).Add(d, d) - -func (v *projCached) FromP3(p *Point) *projCached { - v.YplusX.Add(&p.y, &p.x) - v.YminusX.Subtract(&p.y, &p.x) - v.Z.Set(&p.z) - v.T2d.Multiply(&p.t, d2) - return v -} - -func (v *affineCached) FromP3(p *Point) *affineCached { - v.YplusX.Add(&p.y, &p.x) - v.YminusX.Subtract(&p.y, &p.x) - v.T2d.Multiply(&p.t, d2) - - var invZ field.Element - invZ.Invert(&p.z) - v.YplusX.Multiply(&v.YplusX, &invZ) - v.YminusX.Multiply(&v.YminusX, &invZ) - v.T2d.Multiply(&v.T2d, &invZ) - return v -} - -// (Re)addition and subtraction. - -// Add sets v = p + q, and returns v. -func (v *Point) Add(p, q *Point) *Point { - checkInitialized(p, q) - qCached := new(projCached).FromP3(q) - result := new(projP1xP1).Add(p, qCached) - return v.fromP1xP1(result) -} - -// Subtract sets v = p - q, and returns v. -func (v *Point) Subtract(p, q *Point) *Point { - checkInitialized(p, q) - qCached := new(projCached).FromP3(q) - result := new(projP1xP1).Sub(p, qCached) - return v.fromP1xP1(result) -} - -func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 { - var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element - - YplusX.Add(&p.y, &p.x) - YminusX.Subtract(&p.y, &p.x) - - PP.Multiply(&YplusX, &q.YplusX) - MM.Multiply(&YminusX, &q.YminusX) - TT2d.Multiply(&p.t, &q.T2d) - ZZ2.Multiply(&p.z, &q.Z) - - ZZ2.Add(&ZZ2, &ZZ2) - - v.X.Subtract(&PP, &MM) - v.Y.Add(&PP, &MM) - v.Z.Add(&ZZ2, &TT2d) - v.T.Subtract(&ZZ2, &TT2d) - return v -} - -func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 { - var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element - - YplusX.Add(&p.y, &p.x) - YminusX.Subtract(&p.y, &p.x) - - PP.Multiply(&YplusX, &q.YminusX) // flipped sign - MM.Multiply(&YminusX, &q.YplusX) // flipped sign - TT2d.Multiply(&p.t, &q.T2d) - ZZ2.Multiply(&p.z, &q.Z) - - ZZ2.Add(&ZZ2, &ZZ2) - - v.X.Subtract(&PP, &MM) - v.Y.Add(&PP, &MM) - v.Z.Subtract(&ZZ2, &TT2d) // flipped sign - v.T.Add(&ZZ2, &TT2d) // flipped sign - return v -} - -func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 { - var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element - - YplusX.Add(&p.y, &p.x) - YminusX.Subtract(&p.y, &p.x) - - PP.Multiply(&YplusX, &q.YplusX) - MM.Multiply(&YminusX, &q.YminusX) - TT2d.Multiply(&p.t, &q.T2d) - - Z2.Add(&p.z, &p.z) - - v.X.Subtract(&PP, &MM) - v.Y.Add(&PP, &MM) - v.Z.Add(&Z2, &TT2d) - v.T.Subtract(&Z2, &TT2d) - return v -} - -func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 { - var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element - - YplusX.Add(&p.y, &p.x) - YminusX.Subtract(&p.y, &p.x) - - PP.Multiply(&YplusX, &q.YminusX) // flipped sign - MM.Multiply(&YminusX, &q.YplusX) // flipped sign - TT2d.Multiply(&p.t, &q.T2d) - - Z2.Add(&p.z, &p.z) - - v.X.Subtract(&PP, &MM) - v.Y.Add(&PP, &MM) - v.Z.Subtract(&Z2, &TT2d) // flipped sign - v.T.Add(&Z2, &TT2d) // flipped sign - return v -} - -// Doubling. - -func (v *projP1xP1) Double(p *projP2) *projP1xP1 { - var XX, YY, ZZ2, XplusYsq field.Element - - XX.Square(&p.X) - YY.Square(&p.Y) - ZZ2.Square(&p.Z) - ZZ2.Add(&ZZ2, &ZZ2) - XplusYsq.Add(&p.X, &p.Y) - XplusYsq.Square(&XplusYsq) - - v.Y.Add(&YY, &XX) - v.Z.Subtract(&YY, &XX) - - v.X.Subtract(&XplusYsq, &v.Y) - v.T.Subtract(&ZZ2, &v.Z) - return v -} - -// Negation. - -// Negate sets v = -p, and returns v. -func (v *Point) Negate(p *Point) *Point { - checkInitialized(p) - v.x.Negate(&p.x) - v.y.Set(&p.y) - v.z.Set(&p.z) - v.t.Negate(&p.t) - return v -} - -// Equal returns 1 if v is equivalent to u, and 0 otherwise. -func (v *Point) Equal(u *Point) int { - checkInitialized(v, u) - - var t1, t2, t3, t4 field.Element - t1.Multiply(&v.x, &u.z) - t2.Multiply(&u.x, &v.z) - t3.Multiply(&v.y, &u.z) - t4.Multiply(&u.y, &v.z) - - return t1.Equal(&t2) & t3.Equal(&t4) -} - -// Constant-time operations - -// Select sets v to a if cond == 1 and to b if cond == 0. -func (v *projCached) Select(a, b *projCached, cond int) *projCached { - v.YplusX.Select(&a.YplusX, &b.YplusX, cond) - v.YminusX.Select(&a.YminusX, &b.YminusX, cond) - v.Z.Select(&a.Z, &b.Z, cond) - v.T2d.Select(&a.T2d, &b.T2d, cond) - return v -} - -// Select sets v to a if cond == 1 and to b if cond == 0. -func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached { - v.YplusX.Select(&a.YplusX, &b.YplusX, cond) - v.YminusX.Select(&a.YminusX, &b.YminusX, cond) - v.T2d.Select(&a.T2d, &b.T2d, cond) - return v -} - -// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. -func (v *projCached) CondNeg(cond int) *projCached { - v.YplusX.Swap(&v.YminusX, cond) - v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) - return v -} - -// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. -func (v *affineCached) CondNeg(cond int) *affineCached { - v.YplusX.Swap(&v.YminusX, cond) - v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) - return v -} diff --git a/vendor/filippo.io/edwards25519/extra.go b/vendor/filippo.io/edwards25519/extra.go deleted file mode 100644 index d152d68..0000000 --- a/vendor/filippo.io/edwards25519/extra.go +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright (c) 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package edwards25519 - -// This file contains additional functionality that is not included in the -// upstream crypto/internal/edwards25519 package. - -import ( - "errors" - - "filippo.io/edwards25519/field" -) - -// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where -// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522. -func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) { - // This function is outlined to make the allocations inline in the caller - // rather than happen on the heap. Don't change the style without making - // sure it doesn't increase the inliner cost. - var e [4]field.Element - X, Y, Z, T = v.extendedCoordinates(&e) - return -} - -func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) { - checkInitialized(v) - X = e[0].Set(&v.x) - Y = e[1].Set(&v.y) - Z = e[2].Set(&v.z) - T = e[3].Set(&v.t) - return -} - -// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where -// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522. -// -// If the coordinates are invalid or don't represent a valid point on the curve, -// SetExtendedCoordinates returns nil and an error and the receiver is -// unchanged. Otherwise, SetExtendedCoordinates returns v. -func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) { - if !isOnCurve(X, Y, Z, T) { - return nil, errors.New("edwards25519: invalid point coordinates") - } - v.x.Set(X) - v.y.Set(Y) - v.z.Set(Z) - v.t.Set(T) - return v, nil -} - -func isOnCurve(X, Y, Z, T *field.Element) bool { - var lhs, rhs field.Element - XX := new(field.Element).Square(X) - YY := new(field.Element).Square(Y) - ZZ := new(field.Element).Square(Z) - TT := new(field.Element).Square(T) - // -x² + y² = 1 + dx²y² - // -(X/Z)² + (Y/Z)² = 1 + d(T/Z)² - // -X² + Y² = Z² + dT² - lhs.Subtract(YY, XX) - rhs.Multiply(d, TT).Add(&rhs, ZZ) - if lhs.Equal(&rhs) != 1 { - return false - } - // xy = T/Z - // XY/Z² = T/Z - // XY = TZ - lhs.Multiply(X, Y) - rhs.Multiply(T, Z) - return lhs.Equal(&rhs) == 1 -} - -// BytesMontgomery converts v to a point on the birationally-equivalent -// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding -// according to RFC 7748. -// -// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode -// to the same value. If v is the identity point, BytesMontgomery returns 32 -// zero bytes, analogously to the X25519 function. -// -// The lack of an inverse operation (such as SetMontgomeryBytes) is deliberate: -// while every valid edwards25519 point has a unique u-coordinate Montgomery -// encoding, X25519 accepts inputs on the quadratic twist, which don't correspond -// to any edwards25519 point, and every other X25519 input corresponds to two -// edwards25519 points. -func (v *Point) BytesMontgomery() []byte { - // This function is outlined to make the allocations inline in the caller - // rather than happen on the heap. - var buf [32]byte - return v.bytesMontgomery(&buf) -} - -func (v *Point) bytesMontgomery(buf *[32]byte) []byte { - checkInitialized(v) - - // RFC 7748, Section 4.1 provides the bilinear map to calculate the - // Montgomery u-coordinate - // - // u = (1 + y) / (1 - y) - // - // where y = Y / Z. - - var y, recip, u field.Element - - y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z - recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y) - u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r - - return copyFieldElement(buf, &u) -} - -// MultByCofactor sets v = 8 * p, and returns v. -func (v *Point) MultByCofactor(p *Point) *Point { - checkInitialized(p) - result := projP1xP1{} - pp := (&projP2{}).FromP3(p) - result.Double(pp) - pp.FromP1xP1(&result) - result.Double(pp) - pp.FromP1xP1(&result) - result.Double(pp) - return v.fromP1xP1(&result) -} - -// Given k > 0, set s = s**(2*i). -func (s *Scalar) pow2k(k int) { - for i := 0; i < k; i++ { - s.Multiply(s, s) - } -} - -// Invert sets s to the inverse of a nonzero scalar v, and returns s. -// -// If t is zero, Invert returns zero. -func (s *Scalar) Invert(t *Scalar) *Scalar { - // Uses a hardcoded sliding window of width 4. - var table [8]Scalar - var tt Scalar - tt.Multiply(t, t) - table[0] = *t - for i := 0; i < 7; i++ { - table[i+1].Multiply(&table[i], &tt) - } - // Now table = [t**1, t**3, t**5, t**7, t**9, t**11, t**13, t**15] - // so t**k = t[k/2] for odd k - - // To compute the sliding window digits, use the following Sage script: - - // sage: import itertools - // sage: def sliding_window(w,k): - // ....: digits = [] - // ....: while k > 0: - // ....: if k % 2 == 1: - // ....: kmod = k % (2**w) - // ....: digits.append(kmod) - // ....: k = k - kmod - // ....: else: - // ....: digits.append(0) - // ....: k = k // 2 - // ....: return digits - - // Now we can compute s roughly as follows: - - // sage: s = 1 - // sage: for coeff in reversed(sliding_window(4,l-2)): - // ....: s = s*s - // ....: if coeff > 0 : - // ....: s = s*t**coeff - - // This works on one bit at a time, with many runs of zeros. - // The digits can be collapsed into [(count, coeff)] as follows: - - // sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))] - - // Entries of the form (k, 0) turn into pow2k(k) - // Entries of the form (1, coeff) turn into a squaring and then a table lookup. - // We can fold the squaring into the previous pow2k(k) as pow2k(k+1). - - *s = table[1/2] - s.pow2k(127 + 1) - s.Multiply(s, &table[1/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[9/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[11/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[13/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[15/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[7/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[15/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[5/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[1/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[15/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[15/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[7/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[3/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[11/2]) - s.pow2k(5 + 1) - s.Multiply(s, &table[11/2]) - s.pow2k(9 + 1) - s.Multiply(s, &table[9/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[3/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[3/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[3/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[9/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[7/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[3/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[13/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[7/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[9/2]) - s.pow2k(3 + 1) - s.Multiply(s, &table[15/2]) - s.pow2k(4 + 1) - s.Multiply(s, &table[11/2]) - - return s -} - -// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v. -// -// Execution time depends only on the lengths of the two slices, which must match. -func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point { - if len(scalars) != len(points) { - panic("edwards25519: called MultiScalarMult with different size inputs") - } - checkInitialized(points...) - - // Proceed as in the single-base case, but share doublings - // between each point in the multiscalar equation. - - // Build lookup tables for each point - tables := make([]projLookupTable, len(points)) - for i := range tables { - tables[i].FromP3(points[i]) - } - // Compute signed radix-16 digits for each scalar - digits := make([][64]int8, len(scalars)) - for i := range digits { - digits[i] = scalars[i].signedRadix16() - } - - // Unwrap first loop iteration to save computing 16*identity - multiple := &projCached{} - tmp1 := &projP1xP1{} - tmp2 := &projP2{} - // Lookup-and-add the appropriate multiple of each input point - for j := range tables { - tables[j].SelectInto(multiple, digits[j][63]) - tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords - v.fromP1xP1(tmp1) // update v - } - tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration - for i := 62; i >= 0; i-- { - tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords - v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords - // Lookup-and-add the appropriate multiple of each input point - for j := range tables { - tables[j].SelectInto(multiple, digits[j][i]) - tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords - v.fromP1xP1(tmp1) // update v - } - tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration - } - return v -} - -// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v. -// -// Execution time depends on the inputs. -func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point { - if len(scalars) != len(points) { - panic("edwards25519: called VarTimeMultiScalarMult with different size inputs") - } - checkInitialized(points...) - - // Generalize double-base NAF computation to arbitrary sizes. - // Here all the points are dynamic, so we only use the smaller - // tables. - - // Build lookup tables for each point - tables := make([]nafLookupTable5, len(points)) - for i := range tables { - tables[i].FromP3(points[i]) - } - // Compute a NAF for each scalar - nafs := make([][256]int8, len(scalars)) - for i := range nafs { - nafs[i] = scalars[i].nonAdjacentForm(5) - } - - multiple := &projCached{} - tmp1 := &projP1xP1{} - tmp2 := &projP2{} - tmp2.Zero() - - // Move from high to low bits, doubling the accumulator - // at each iteration and checking whether there is a nonzero - // coefficient to look up a multiple of. - // - // Skip trying to find the first nonzero coefficent, because - // searching might be more work than a few extra doublings. - for i := 255; i >= 0; i-- { - tmp1.Double(tmp2) - - for j := range nafs { - if nafs[j][i] > 0 { - v.fromP1xP1(tmp1) - tables[j].SelectInto(multiple, nafs[j][i]) - tmp1.Add(v, multiple) - } else if nafs[j][i] < 0 { - v.fromP1xP1(tmp1) - tables[j].SelectInto(multiple, -nafs[j][i]) - tmp1.Sub(v, multiple) - } - } - - tmp2.FromP1xP1(tmp1) - } - - v.fromP2(tmp2) - return v -} diff --git a/vendor/filippo.io/edwards25519/field/fe.go b/vendor/filippo.io/edwards25519/field/fe.go deleted file mode 100644 index 5518ef2..0000000 --- a/vendor/filippo.io/edwards25519/field/fe.go +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package field implements fast arithmetic modulo 2^255-19. -package field - -import ( - "crypto/subtle" - "encoding/binary" - "errors" - "math/bits" -) - -// Element represents an element of the field GF(2^255-19). Note that this -// is not a cryptographically secure group, and should only be used to interact -// with edwards25519.Point coordinates. -// -// This type works similarly to math/big.Int, and all arguments and receivers -// are allowed to alias. -// -// The zero value is a valid zero element. -type Element struct { - // An element t represents the integer - // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204 - // - // Between operations, all limbs are expected to be lower than 2^52. - l0 uint64 - l1 uint64 - l2 uint64 - l3 uint64 - l4 uint64 -} - -const maskLow51Bits uint64 = (1 << 51) - 1 - -var feZero = &Element{0, 0, 0, 0, 0} - -// Zero sets v = 0, and returns v. -func (v *Element) Zero() *Element { - *v = *feZero - return v -} - -var feOne = &Element{1, 0, 0, 0, 0} - -// One sets v = 1, and returns v. -func (v *Element) One() *Element { - *v = *feOne - return v -} - -// reduce reduces v modulo 2^255 - 19 and returns it. -func (v *Element) reduce() *Element { - v.carryPropagate() - - // After the light reduction we now have a field element representation - // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19. - - // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1, - // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise. - c := (v.l0 + 19) >> 51 - c = (v.l1 + c) >> 51 - c = (v.l2 + c) >> 51 - c = (v.l3 + c) >> 51 - c = (v.l4 + c) >> 51 - - // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's - // effectively applying the reduction identity to the carry. - v.l0 += 19 * c - - v.l1 += v.l0 >> 51 - v.l0 = v.l0 & maskLow51Bits - v.l2 += v.l1 >> 51 - v.l1 = v.l1 & maskLow51Bits - v.l3 += v.l2 >> 51 - v.l2 = v.l2 & maskLow51Bits - v.l4 += v.l3 >> 51 - v.l3 = v.l3 & maskLow51Bits - // no additional carry - v.l4 = v.l4 & maskLow51Bits - - return v -} - -// Add sets v = a + b, and returns v. -func (v *Element) Add(a, b *Element) *Element { - v.l0 = a.l0 + b.l0 - v.l1 = a.l1 + b.l1 - v.l2 = a.l2 + b.l2 - v.l3 = a.l3 + b.l3 - v.l4 = a.l4 + b.l4 - // Using the generic implementation here is actually faster than the - // assembly. Probably because the body of this function is so simple that - // the compiler can figure out better optimizations by inlining the carry - // propagation. - return v.carryPropagateGeneric() -} - -// Subtract sets v = a - b, and returns v. -func (v *Element) Subtract(a, b *Element) *Element { - // We first add 2 * p, to guarantee the subtraction won't underflow, and - // then subtract b (which can be up to 2^255 + 2^13 * 19). - v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0 - v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1 - v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2 - v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3 - v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4 - return v.carryPropagate() -} - -// Negate sets v = -a, and returns v. -func (v *Element) Negate(a *Element) *Element { - return v.Subtract(feZero, a) -} - -// Invert sets v = 1/z mod p, and returns v. -// -// If z == 0, Invert returns v = 0. -func (v *Element) Invert(z *Element) *Element { - // Inversion is implemented as exponentiation with exponent p − 2. It uses the - // same sequence of 255 squarings and 11 multiplications as [Curve25519]. - var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element - - z2.Square(z) // 2 - t.Square(&z2) // 4 - t.Square(&t) // 8 - z9.Multiply(&t, z) // 9 - z11.Multiply(&z9, &z2) // 11 - t.Square(&z11) // 22 - z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 - - t.Square(&z2_5_0) // 2^6 - 2^1 - for i := 0; i < 4; i++ { - t.Square(&t) // 2^10 - 2^5 - } - z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 - - t.Square(&z2_10_0) // 2^11 - 2^1 - for i := 0; i < 9; i++ { - t.Square(&t) // 2^20 - 2^10 - } - z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 - - t.Square(&z2_20_0) // 2^21 - 2^1 - for i := 0; i < 19; i++ { - t.Square(&t) // 2^40 - 2^20 - } - t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 - - t.Square(&t) // 2^41 - 2^1 - for i := 0; i < 9; i++ { - t.Square(&t) // 2^50 - 2^10 - } - z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 - - t.Square(&z2_50_0) // 2^51 - 2^1 - for i := 0; i < 49; i++ { - t.Square(&t) // 2^100 - 2^50 - } - z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 - - t.Square(&z2_100_0) // 2^101 - 2^1 - for i := 0; i < 99; i++ { - t.Square(&t) // 2^200 - 2^100 - } - t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 - - t.Square(&t) // 2^201 - 2^1 - for i := 0; i < 49; i++ { - t.Square(&t) // 2^250 - 2^50 - } - t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 - - t.Square(&t) // 2^251 - 2^1 - t.Square(&t) // 2^252 - 2^2 - t.Square(&t) // 2^253 - 2^3 - t.Square(&t) // 2^254 - 2^4 - t.Square(&t) // 2^255 - 2^5 - - return v.Multiply(&t, &z11) // 2^255 - 21 -} - -// Set sets v = a, and returns v. -func (v *Element) Set(a *Element) *Element { - *v = *a - return v -} - -// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is -// not of the right length, SetBytes returns nil and an error, and the -// receiver is unchanged. -// -// Consistent with RFC 7748, the most significant bit (the high bit of the -// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1) -// are accepted. Note that this is laxer than specified by RFC 8032, but -// consistent with most Ed25519 implementations. -func (v *Element) SetBytes(x []byte) (*Element, error) { - if len(x) != 32 { - return nil, errors.New("edwards25519: invalid field element input size") - } - - // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). - v.l0 = binary.LittleEndian.Uint64(x[0:8]) - v.l0 &= maskLow51Bits - // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). - v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 - v.l1 &= maskLow51Bits - // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). - v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 - v.l2 &= maskLow51Bits - // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). - v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 - v.l3 &= maskLow51Bits - // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51). - // Note: not bytes 25:33, shift 4, to avoid overread. - v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 - v.l4 &= maskLow51Bits - - return v, nil -} - -// Bytes returns the canonical 32-byte little-endian encoding of v. -func (v *Element) Bytes() []byte { - // This function is outlined to make the allocations inline in the caller - // rather than happen on the heap. - var out [32]byte - return v.bytes(&out) -} - -func (v *Element) bytes(out *[32]byte) []byte { - t := *v - t.reduce() - - var buf [8]byte - for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { - bitsOffset := i * 51 - binary.LittleEndian.PutUint64(buf[:], l<= len(out) { - break - } - out[off] |= bb - } - } - - return out[:] -} - -// Equal returns 1 if v and u are equal, and 0 otherwise. -func (v *Element) Equal(u *Element) int { - sa, sv := u.Bytes(), v.Bytes() - return subtle.ConstantTimeCompare(sa, sv) -} - -// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise. -func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) } - -// Select sets v to a if cond == 1, and to b if cond == 0. -func (v *Element) Select(a, b *Element, cond int) *Element { - m := mask64Bits(cond) - v.l0 = (m & a.l0) | (^m & b.l0) - v.l1 = (m & a.l1) | (^m & b.l1) - v.l2 = (m & a.l2) | (^m & b.l2) - v.l3 = (m & a.l3) | (^m & b.l3) - v.l4 = (m & a.l4) | (^m & b.l4) - return v -} - -// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v. -func (v *Element) Swap(u *Element, cond int) { - m := mask64Bits(cond) - t := m & (v.l0 ^ u.l0) - v.l0 ^= t - u.l0 ^= t - t = m & (v.l1 ^ u.l1) - v.l1 ^= t - u.l1 ^= t - t = m & (v.l2 ^ u.l2) - v.l2 ^= t - u.l2 ^= t - t = m & (v.l3 ^ u.l3) - v.l3 ^= t - u.l3 ^= t - t = m & (v.l4 ^ u.l4) - v.l4 ^= t - u.l4 ^= t -} - -// IsNegative returns 1 if v is negative, and 0 otherwise. -func (v *Element) IsNegative() int { - return int(v.Bytes()[0] & 1) -} - -// Absolute sets v to |u|, and returns v. -func (v *Element) Absolute(u *Element) *Element { - return v.Select(new(Element).Negate(u), u, u.IsNegative()) -} - -// Multiply sets v = x * y, and returns v. -func (v *Element) Multiply(x, y *Element) *Element { - feMul(v, x, y) - return v -} - -// Square sets v = x * x, and returns v. -func (v *Element) Square(x *Element) *Element { - feSquare(v, x) - return v -} - -// Mult32 sets v = x * y, and returns v. -func (v *Element) Mult32(x *Element, y uint32) *Element { - x0lo, x0hi := mul51(x.l0, y) - x1lo, x1hi := mul51(x.l1, y) - x2lo, x2hi := mul51(x.l2, y) - x3lo, x3hi := mul51(x.l3, y) - x4lo, x4hi := mul51(x.l4, y) - v.l0 = x0lo + 19*x4hi // carried over per the reduction identity - v.l1 = x1lo + x0hi - v.l2 = x2lo + x1hi - v.l3 = x3lo + x2hi - v.l4 = x4lo + x3hi - // The hi portions are going to be only 32 bits, plus any previous excess, - // so we can skip the carry propagation. - return v -} - -// mul51 returns lo + hi * 2⁵¹ = a * b. -func mul51(a uint64, b uint32) (lo uint64, hi uint64) { - mh, ml := bits.Mul64(a, uint64(b)) - lo = ml & maskLow51Bits - hi = (mh << 13) | (ml >> 51) - return -} - -// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3. -func (v *Element) Pow22523(x *Element) *Element { - var t0, t1, t2 Element - - t0.Square(x) // x^2 - t1.Square(&t0) // x^4 - t1.Square(&t1) // x^8 - t1.Multiply(x, &t1) // x^9 - t0.Multiply(&t0, &t1) // x^11 - t0.Square(&t0) // x^22 - t0.Multiply(&t1, &t0) // x^31 - t1.Square(&t0) // x^62 - for i := 1; i < 5; i++ { // x^992 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 - t1.Square(&t0) // 2^11 - 2 - for i := 1; i < 10; i++ { // 2^20 - 2^10 - t1.Square(&t1) - } - t1.Multiply(&t1, &t0) // 2^20 - 1 - t2.Square(&t1) // 2^21 - 2 - for i := 1; i < 20; i++ { // 2^40 - 2^20 - t2.Square(&t2) - } - t1.Multiply(&t2, &t1) // 2^40 - 1 - t1.Square(&t1) // 2^41 - 2 - for i := 1; i < 10; i++ { // 2^50 - 2^10 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // 2^50 - 1 - t1.Square(&t0) // 2^51 - 2 - for i := 1; i < 50; i++ { // 2^100 - 2^50 - t1.Square(&t1) - } - t1.Multiply(&t1, &t0) // 2^100 - 1 - t2.Square(&t1) // 2^101 - 2 - for i := 1; i < 100; i++ { // 2^200 - 2^100 - t2.Square(&t2) - } - t1.Multiply(&t2, &t1) // 2^200 - 1 - t1.Square(&t1) // 2^201 - 2 - for i := 1; i < 50; i++ { // 2^250 - 2^50 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // 2^250 - 1 - t0.Square(&t0) // 2^251 - 2 - t0.Square(&t0) // 2^252 - 4 - return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) -} - -// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. -var sqrtM1 = &Element{1718705420411056, 234908883556509, - 2233514472574048, 2117202627021982, 765476049583133} - -// SqrtRatio sets r to the non-negative square root of the ratio of u and v. -// -// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio -// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, -// and returns r and 0. -func (r *Element) SqrtRatio(u, v *Element) (R *Element, wasSquare int) { - t0 := new(Element) - - // r = (u * v3) * (u * v7)^((p-5)/8) - v2 := new(Element).Square(v) - uv3 := new(Element).Multiply(u, t0.Multiply(v2, v)) - uv7 := new(Element).Multiply(uv3, t0.Square(v2)) - rr := new(Element).Multiply(uv3, t0.Pow22523(uv7)) - - check := new(Element).Multiply(v, t0.Square(rr)) // check = v * r^2 - - uNeg := new(Element).Negate(u) - correctSignSqrt := check.Equal(u) - flippedSignSqrt := check.Equal(uNeg) - flippedSignSqrtI := check.Equal(t0.Multiply(uNeg, sqrtM1)) - - rPrime := new(Element).Multiply(rr, sqrtM1) // r_prime = SQRT_M1 * r - // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) - rr.Select(rPrime, rr, flippedSignSqrt|flippedSignSqrtI) - - r.Absolute(rr) // Choose the nonnegative square root. - return r, correctSignSqrt | flippedSignSqrt -} diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.go b/vendor/filippo.io/edwards25519/field/fe_amd64.go deleted file mode 100644 index edcf163..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_amd64.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. - -//go:build amd64 && gc && !purego -// +build amd64,gc,!purego - -package field - -// feMul sets out = a * b. It works like feMulGeneric. -// -//go:noescape -func feMul(out *Element, a *Element, b *Element) - -// feSquare sets out = a * a. It works like feSquareGeneric. -// -//go:noescape -func feSquare(out *Element, a *Element) diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.s b/vendor/filippo.io/edwards25519/field/fe_amd64.s deleted file mode 100644 index 293f013..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_amd64.s +++ /dev/null @@ -1,379 +0,0 @@ -// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. - -//go:build amd64 && gc && !purego -// +build amd64,gc,!purego - -#include "textflag.h" - -// func feMul(out *Element, a *Element, b *Element) -TEXT ·feMul(SB), NOSPLIT, $0-24 - MOVQ a+8(FP), CX - MOVQ b+16(FP), BX - - // r0 = a0×b0 - MOVQ (CX), AX - MULQ (BX) - MOVQ AX, DI - MOVQ DX, SI - - // r0 += 19×a1×b4 - MOVQ 8(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r0 += 19×a2×b3 - MOVQ 16(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r0 += 19×a3×b2 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 16(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r0 += 19×a4×b1 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 8(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r1 = a0×b1 - MOVQ (CX), AX - MULQ 8(BX) - MOVQ AX, R9 - MOVQ DX, R8 - - // r1 += a1×b0 - MOVQ 8(CX), AX - MULQ (BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r1 += 19×a2×b4 - MOVQ 16(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r1 += 19×a3×b3 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r1 += 19×a4×b2 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 16(BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r2 = a0×b2 - MOVQ (CX), AX - MULQ 16(BX) - MOVQ AX, R11 - MOVQ DX, R10 - - // r2 += a1×b1 - MOVQ 8(CX), AX - MULQ 8(BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r2 += a2×b0 - MOVQ 16(CX), AX - MULQ (BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r2 += 19×a3×b4 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r2 += 19×a4×b3 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r3 = a0×b3 - MOVQ (CX), AX - MULQ 24(BX) - MOVQ AX, R13 - MOVQ DX, R12 - - // r3 += a1×b2 - MOVQ 8(CX), AX - MULQ 16(BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r3 += a2×b1 - MOVQ 16(CX), AX - MULQ 8(BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r3 += a3×b0 - MOVQ 24(CX), AX - MULQ (BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r3 += 19×a4×b4 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r4 = a0×b4 - MOVQ (CX), AX - MULQ 32(BX) - MOVQ AX, R15 - MOVQ DX, R14 - - // r4 += a1×b3 - MOVQ 8(CX), AX - MULQ 24(BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // r4 += a2×b2 - MOVQ 16(CX), AX - MULQ 16(BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // r4 += a3×b1 - MOVQ 24(CX), AX - MULQ 8(BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // r4 += a4×b0 - MOVQ 32(CX), AX - MULQ (BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // First reduction chain - MOVQ $0x0007ffffffffffff, AX - SHLQ $0x0d, DI, SI - SHLQ $0x0d, R9, R8 - SHLQ $0x0d, R11, R10 - SHLQ $0x0d, R13, R12 - SHLQ $0x0d, R15, R14 - ANDQ AX, DI - IMUL3Q $0x13, R14, R14 - ADDQ R14, DI - ANDQ AX, R9 - ADDQ SI, R9 - ANDQ AX, R11 - ADDQ R8, R11 - ANDQ AX, R13 - ADDQ R10, R13 - ANDQ AX, R15 - ADDQ R12, R15 - - // Second reduction chain (carryPropagate) - MOVQ DI, SI - SHRQ $0x33, SI - MOVQ R9, R8 - SHRQ $0x33, R8 - MOVQ R11, R10 - SHRQ $0x33, R10 - MOVQ R13, R12 - SHRQ $0x33, R12 - MOVQ R15, R14 - SHRQ $0x33, R14 - ANDQ AX, DI - IMUL3Q $0x13, R14, R14 - ADDQ R14, DI - ANDQ AX, R9 - ADDQ SI, R9 - ANDQ AX, R11 - ADDQ R8, R11 - ANDQ AX, R13 - ADDQ R10, R13 - ANDQ AX, R15 - ADDQ R12, R15 - - // Store output - MOVQ out+0(FP), AX - MOVQ DI, (AX) - MOVQ R9, 8(AX) - MOVQ R11, 16(AX) - MOVQ R13, 24(AX) - MOVQ R15, 32(AX) - RET - -// func feSquare(out *Element, a *Element) -TEXT ·feSquare(SB), NOSPLIT, $0-16 - MOVQ a+8(FP), CX - - // r0 = l0×l0 - MOVQ (CX), AX - MULQ (CX) - MOVQ AX, SI - MOVQ DX, BX - - // r0 += 38×l1×l4 - MOVQ 8(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, SI - ADCQ DX, BX - - // r0 += 38×l2×l3 - MOVQ 16(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 24(CX) - ADDQ AX, SI - ADCQ DX, BX - - // r1 = 2×l0×l1 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 8(CX) - MOVQ AX, R8 - MOVQ DX, DI - - // r1 += 38×l2×l4 - MOVQ 16(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, R8 - ADCQ DX, DI - - // r1 += 19×l3×l3 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(CX) - ADDQ AX, R8 - ADCQ DX, DI - - // r2 = 2×l0×l2 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 16(CX) - MOVQ AX, R10 - MOVQ DX, R9 - - // r2 += l1×l1 - MOVQ 8(CX), AX - MULQ 8(CX) - ADDQ AX, R10 - ADCQ DX, R9 - - // r2 += 38×l3×l4 - MOVQ 24(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, R10 - ADCQ DX, R9 - - // r3 = 2×l0×l3 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 24(CX) - MOVQ AX, R12 - MOVQ DX, R11 - - // r3 += 2×l1×l2 - MOVQ 8(CX), AX - IMUL3Q $0x02, AX, AX - MULQ 16(CX) - ADDQ AX, R12 - ADCQ DX, R11 - - // r3 += 19×l4×l4 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(CX) - ADDQ AX, R12 - ADCQ DX, R11 - - // r4 = 2×l0×l4 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 32(CX) - MOVQ AX, R14 - MOVQ DX, R13 - - // r4 += 2×l1×l3 - MOVQ 8(CX), AX - IMUL3Q $0x02, AX, AX - MULQ 24(CX) - ADDQ AX, R14 - ADCQ DX, R13 - - // r4 += l2×l2 - MOVQ 16(CX), AX - MULQ 16(CX) - ADDQ AX, R14 - ADCQ DX, R13 - - // First reduction chain - MOVQ $0x0007ffffffffffff, AX - SHLQ $0x0d, SI, BX - SHLQ $0x0d, R8, DI - SHLQ $0x0d, R10, R9 - SHLQ $0x0d, R12, R11 - SHLQ $0x0d, R14, R13 - ANDQ AX, SI - IMUL3Q $0x13, R13, R13 - ADDQ R13, SI - ANDQ AX, R8 - ADDQ BX, R8 - ANDQ AX, R10 - ADDQ DI, R10 - ANDQ AX, R12 - ADDQ R9, R12 - ANDQ AX, R14 - ADDQ R11, R14 - - // Second reduction chain (carryPropagate) - MOVQ SI, BX - SHRQ $0x33, BX - MOVQ R8, DI - SHRQ $0x33, DI - MOVQ R10, R9 - SHRQ $0x33, R9 - MOVQ R12, R11 - SHRQ $0x33, R11 - MOVQ R14, R13 - SHRQ $0x33, R13 - ANDQ AX, SI - IMUL3Q $0x13, R13, R13 - ADDQ R13, SI - ANDQ AX, R8 - ADDQ BX, R8 - ANDQ AX, R10 - ADDQ DI, R10 - ANDQ AX, R12 - ADDQ R9, R12 - ANDQ AX, R14 - ADDQ R11, R14 - - // Store output - MOVQ out+0(FP), AX - MOVQ SI, (AX) - MOVQ R8, 8(AX) - MOVQ R10, 16(AX) - MOVQ R12, 24(AX) - MOVQ R14, 32(AX) - RET diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go deleted file mode 100644 index ddb6c9b..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !amd64 || !gc || purego -// +build !amd64 !gc purego - -package field - -func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } - -func feSquare(v, x *Element) { feSquareGeneric(v, x) } diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.go b/vendor/filippo.io/edwards25519/field/fe_arm64.go deleted file mode 100644 index af459ef..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_arm64.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build arm64 && gc && !purego -// +build arm64,gc,!purego - -package field - -//go:noescape -func carryPropagate(v *Element) - -func (v *Element) carryPropagate() *Element { - carryPropagate(v) - return v -} diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.s b/vendor/filippo.io/edwards25519/field/fe_arm64.s deleted file mode 100644 index 3126a43..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_arm64.s +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build arm64 && gc && !purego - -#include "textflag.h" - -// carryPropagate works exactly like carryPropagateGeneric and uses the -// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but -// avoids loading R0-R4 twice and uses LDP and STP. -// -// See https://golang.org/issues/43145 for the main compiler issue. -// -// func carryPropagate(v *Element) -TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8 - MOVD v+0(FP), R20 - - LDP 0(R20), (R0, R1) - LDP 16(R20), (R2, R3) - MOVD 32(R20), R4 - - AND $0x7ffffffffffff, R0, R10 - AND $0x7ffffffffffff, R1, R11 - AND $0x7ffffffffffff, R2, R12 - AND $0x7ffffffffffff, R3, R13 - AND $0x7ffffffffffff, R4, R14 - - ADD R0>>51, R11, R11 - ADD R1>>51, R12, R12 - ADD R2>>51, R13, R13 - ADD R3>>51, R14, R14 - // R4>>51 * 19 + R10 -> R10 - LSR $51, R4, R21 - MOVD $19, R22 - MADD R22, R10, R21, R10 - - STP (R10, R11), 0(R20) - STP (R12, R13), 16(R20) - MOVD R14, 32(R20) - - RET diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go deleted file mode 100644 index 234a5b2..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !arm64 || !gc || purego -// +build !arm64 !gc purego - -package field - -func (v *Element) carryPropagate() *Element { - return v.carryPropagateGeneric() -} diff --git a/vendor/filippo.io/edwards25519/field/fe_extra.go b/vendor/filippo.io/edwards25519/field/fe_extra.go deleted file mode 100644 index 1ef503b..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_extra.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package field - -import "errors" - -// This file contains additional functionality that is not included in the -// upstream crypto/ed25519/edwards25519/field package. - -// SetWideBytes sets v to x, where x is a 64-byte little-endian encoding, which -// is reduced modulo the field order. If x is not of the right length, -// SetWideBytes returns nil and an error, and the receiver is unchanged. -// -// SetWideBytes is not necessary to select a uniformly distributed value, and is -// only provided for compatibility: SetBytes can be used instead as the chance -// of bias is less than 2⁻²⁵⁰. -func (v *Element) SetWideBytes(x []byte) (*Element, error) { - if len(x) != 64 { - return nil, errors.New("edwards25519: invalid SetWideBytes input size") - } - - // Split the 64 bytes into two elements, and extract the most significant - // bit of each, which is ignored by SetBytes. - lo, _ := new(Element).SetBytes(x[:32]) - loMSB := uint64(x[31] >> 7) - hi, _ := new(Element).SetBytes(x[32:]) - hiMSB := uint64(x[63] >> 7) - - // The output we want is - // - // v = lo + loMSB * 2²⁵⁵ + hi * 2²⁵⁶ + hiMSB * 2⁵¹¹ - // - // which applying the reduction identity comes out to - // - // v = lo + loMSB * 19 + hi * 2 * 19 + hiMSB * 2 * 19² - // - // l0 will be the sum of a 52 bits value (lo.l0), plus a 5 bits value - // (loMSB * 19), a 6 bits value (hi.l0 * 2 * 19), and a 10 bits value - // (hiMSB * 2 * 19²), so it fits in a uint64. - - v.l0 = lo.l0 + loMSB*19 + hi.l0*2*19 + hiMSB*2*19*19 - v.l1 = lo.l1 + hi.l1*2*19 - v.l2 = lo.l2 + hi.l2*2*19 - v.l3 = lo.l3 + hi.l3*2*19 - v.l4 = lo.l4 + hi.l4*2*19 - - return v.carryPropagate(), nil -} diff --git a/vendor/filippo.io/edwards25519/field/fe_generic.go b/vendor/filippo.io/edwards25519/field/fe_generic.go deleted file mode 100644 index 86f5fd9..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_generic.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package field - -import "math/bits" - -// uint128 holds a 128-bit number as two 64-bit limbs, for use with the -// bits.Mul64 and bits.Add64 intrinsics. -type uint128 struct { - lo, hi uint64 -} - -// mul64 returns a * b. -func mul64(a, b uint64) uint128 { - hi, lo := bits.Mul64(a, b) - return uint128{lo, hi} -} - -// addMul64 returns v + a * b. -func addMul64(v uint128, a, b uint64) uint128 { - hi, lo := bits.Mul64(a, b) - lo, c := bits.Add64(lo, v.lo, 0) - hi, _ = bits.Add64(hi, v.hi, c) - return uint128{lo, hi} -} - -// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. -func shiftRightBy51(a uint128) uint64 { - return (a.hi << (64 - 51)) | (a.lo >> 51) -} - -func feMulGeneric(v, a, b *Element) { - a0 := a.l0 - a1 := a.l1 - a2 := a.l2 - a3 := a.l3 - a4 := a.l4 - - b0 := b.l0 - b1 := b.l1 - b2 := b.l2 - b3 := b.l3 - b4 := b.l4 - - // Limb multiplication works like pen-and-paper columnar multiplication, but - // with 51-bit limbs instead of digits. - // - // a4 a3 a2 a1 a0 x - // b4 b3 b2 b1 b0 = - // ------------------------ - // a4b0 a3b0 a2b0 a1b0 a0b0 + - // a4b1 a3b1 a2b1 a1b1 a0b1 + - // a4b2 a3b2 a2b2 a1b2 a0b2 + - // a4b3 a3b3 a2b3 a1b3 a0b3 + - // a4b4 a3b4 a2b4 a1b4 a0b4 = - // ---------------------------------------------- - // r8 r7 r6 r5 r4 r3 r2 r1 r0 - // - // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to - // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5, - // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc. - // - // Reduction can be carried out simultaneously to multiplication. For - // example, we do not compute r5: whenever the result of a multiplication - // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0. - // - // a4b0 a3b0 a2b0 a1b0 a0b0 + - // a3b1 a2b1 a1b1 a0b1 19×a4b1 + - // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 + - // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 + - // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 = - // -------------------------------------- - // r4 r3 r2 r1 r0 - // - // Finally we add up the columns into wide, overlapping limbs. - - a1_19 := a1 * 19 - a2_19 := a2 * 19 - a3_19 := a3 * 19 - a4_19 := a4 * 19 - - // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) - r0 := mul64(a0, b0) - r0 = addMul64(r0, a1_19, b4) - r0 = addMul64(r0, a2_19, b3) - r0 = addMul64(r0, a3_19, b2) - r0 = addMul64(r0, a4_19, b1) - - // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2) - r1 := mul64(a0, b1) - r1 = addMul64(r1, a1, b0) - r1 = addMul64(r1, a2_19, b4) - r1 = addMul64(r1, a3_19, b3) - r1 = addMul64(r1, a4_19, b2) - - // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3) - r2 := mul64(a0, b2) - r2 = addMul64(r2, a1, b1) - r2 = addMul64(r2, a2, b0) - r2 = addMul64(r2, a3_19, b4) - r2 = addMul64(r2, a4_19, b3) - - // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4 - r3 := mul64(a0, b3) - r3 = addMul64(r3, a1, b2) - r3 = addMul64(r3, a2, b1) - r3 = addMul64(r3, a3, b0) - r3 = addMul64(r3, a4_19, b4) - - // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 - r4 := mul64(a0, b4) - r4 = addMul64(r4, a1, b3) - r4 = addMul64(r4, a2, b2) - r4 = addMul64(r4, a3, b1) - r4 = addMul64(r4, a4, b0) - - // After the multiplication, we need to reduce (carry) the five coefficients - // to obtain a result with limbs that are at most slightly larger than 2⁵¹, - // to respect the Element invariant. - // - // Overall, the reduction works the same as carryPropagate, except with - // wider inputs: we take the carry for each coefficient by shifting it right - // by 51, and add it to the limb above it. The top carry is multiplied by 19 - // according to the reduction identity and added to the lowest limb. - // - // The largest coefficient (r0) will be at most 111 bits, which guarantees - // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64. - // - // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) - // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²) - // r0 < (1 + 19 × 4) × 2⁵² × 2⁵² - // r0 < 2⁷ × 2⁵² × 2⁵² - // r0 < 2¹¹¹ - // - // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most - // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and - // allows us to easily apply the reduction identity. - // - // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 - // r4 < 5 × 2⁵² × 2⁵² - // r4 < 2¹⁰⁷ - // - - c0 := shiftRightBy51(r0) - c1 := shiftRightBy51(r1) - c2 := shiftRightBy51(r2) - c3 := shiftRightBy51(r3) - c4 := shiftRightBy51(r4) - - rr0 := r0.lo&maskLow51Bits + c4*19 - rr1 := r1.lo&maskLow51Bits + c0 - rr2 := r2.lo&maskLow51Bits + c1 - rr3 := r3.lo&maskLow51Bits + c2 - rr4 := r4.lo&maskLow51Bits + c3 - - // Now all coefficients fit into 64-bit registers but are still too large to - // be passed around as an Element. We therefore do one last carry chain, - // where the carries will be small enough to fit in the wiggle room above 2⁵¹. - *v = Element{rr0, rr1, rr2, rr3, rr4} - v.carryPropagate() -} - -func feSquareGeneric(v, a *Element) { - l0 := a.l0 - l1 := a.l1 - l2 := a.l2 - l3 := a.l3 - l4 := a.l4 - - // Squaring works precisely like multiplication above, but thanks to its - // symmetry we get to group a few terms together. - // - // l4 l3 l2 l1 l0 x - // l4 l3 l2 l1 l0 = - // ------------------------ - // l4l0 l3l0 l2l0 l1l0 l0l0 + - // l4l1 l3l1 l2l1 l1l1 l0l1 + - // l4l2 l3l2 l2l2 l1l2 l0l2 + - // l4l3 l3l3 l2l3 l1l3 l0l3 + - // l4l4 l3l4 l2l4 l1l4 l0l4 = - // ---------------------------------------------- - // r8 r7 r6 r5 r4 r3 r2 r1 r0 - // - // l4l0 l3l0 l2l0 l1l0 l0l0 + - // l3l1 l2l1 l1l1 l0l1 19×l4l1 + - // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 + - // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 + - // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 = - // -------------------------------------- - // r4 r3 r2 r1 r0 - // - // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with - // only three Mul64 and four Add64, instead of five and eight. - - l0_2 := l0 * 2 - l1_2 := l1 * 2 - - l1_38 := l1 * 38 - l2_38 := l2 * 38 - l3_38 := l3 * 38 - - l3_19 := l3 * 19 - l4_19 := l4 * 19 - - // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3) - r0 := mul64(l0, l0) - r0 = addMul64(r0, l1_38, l4) - r0 = addMul64(r0, l2_38, l3) - - // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 - r1 := mul64(l0_2, l1) - r1 = addMul64(r1, l2_38, l4) - r1 = addMul64(r1, l3_19, l3) - - // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4 - r2 := mul64(l0_2, l2) - r2 = addMul64(r2, l1, l1) - r2 = addMul64(r2, l3_38, l4) - - // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 - r3 := mul64(l0_2, l3) - r3 = addMul64(r3, l1_2, l2) - r3 = addMul64(r3, l4_19, l4) - - // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2 - r4 := mul64(l0_2, l4) - r4 = addMul64(r4, l1_2, l3) - r4 = addMul64(r4, l2, l2) - - c0 := shiftRightBy51(r0) - c1 := shiftRightBy51(r1) - c2 := shiftRightBy51(r2) - c3 := shiftRightBy51(r3) - c4 := shiftRightBy51(r4) - - rr0 := r0.lo&maskLow51Bits + c4*19 - rr1 := r1.lo&maskLow51Bits + c0 - rr2 := r2.lo&maskLow51Bits + c1 - rr3 := r3.lo&maskLow51Bits + c2 - rr4 := r4.lo&maskLow51Bits + c3 - - *v = Element{rr0, rr1, rr2, rr3, rr4} - v.carryPropagate() -} - -// carryPropagateGeneric brings the limbs below 52 bits by applying the reduction -// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. -func (v *Element) carryPropagateGeneric() *Element { - c0 := v.l0 >> 51 - c1 := v.l1 >> 51 - c2 := v.l2 >> 51 - c3 := v.l3 >> 51 - c4 := v.l4 >> 51 - - // c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and - // the final l0 will be at most 52 bits. Similarly for the rest. - v.l0 = v.l0&maskLow51Bits + c4*19 - v.l1 = v.l1&maskLow51Bits + c0 - v.l2 = v.l2&maskLow51Bits + c1 - v.l3 = v.l3&maskLow51Bits + c2 - v.l4 = v.l4&maskLow51Bits + c3 - - return v -} diff --git a/vendor/filippo.io/edwards25519/scalar.go b/vendor/filippo.io/edwards25519/scalar.go deleted file mode 100644 index 3fd1653..0000000 --- a/vendor/filippo.io/edwards25519/scalar.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright (c) 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package edwards25519 - -import ( - "encoding/binary" - "errors" -) - -// A Scalar is an integer modulo -// -// l = 2^252 + 27742317777372353535851937790883648493 -// -// which is the prime order of the edwards25519 group. -// -// This type works similarly to math/big.Int, and all arguments and -// receivers are allowed to alias. -// -// The zero value is a valid zero element. -type Scalar struct { - // s is the scalar in the Montgomery domain, in the format of the - // fiat-crypto implementation. - s fiatScalarMontgomeryDomainFieldElement -} - -// The field implementation in scalar_fiat.go is generated by the fiat-crypto -// project (https://github.com/mit-plv/fiat-crypto) at version v0.0.9 (23d2dbc) -// from a formally verified model. -// -// fiat-crypto code comes under the following license. -// -// Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, -// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -// NewScalar returns a new zero Scalar. -func NewScalar() *Scalar { - return &Scalar{} -} - -// MultiplyAdd sets s = x * y + z mod l, and returns s. It is equivalent to -// using Multiply and then Add. -func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar { - // Make a copy of z in case it aliases s. - zCopy := new(Scalar).Set(z) - return s.Multiply(x, y).Add(s, zCopy) -} - -// Add sets s = x + y mod l, and returns s. -func (s *Scalar) Add(x, y *Scalar) *Scalar { - // s = 1 * x + y mod l - fiatScalarAdd(&s.s, &x.s, &y.s) - return s -} - -// Subtract sets s = x - y mod l, and returns s. -func (s *Scalar) Subtract(x, y *Scalar) *Scalar { - // s = -1 * y + x mod l - fiatScalarSub(&s.s, &x.s, &y.s) - return s -} - -// Negate sets s = -x mod l, and returns s. -func (s *Scalar) Negate(x *Scalar) *Scalar { - // s = -1 * x + 0 mod l - fiatScalarOpp(&s.s, &x.s) - return s -} - -// Multiply sets s = x * y mod l, and returns s. -func (s *Scalar) Multiply(x, y *Scalar) *Scalar { - // s = x * y + 0 mod l - fiatScalarMul(&s.s, &x.s, &y.s) - return s -} - -// Set sets s = x, and returns s. -func (s *Scalar) Set(x *Scalar) *Scalar { - *s = *x - return s -} - -// SetUniformBytes sets s = x mod l, where x is a 64-byte little-endian integer. -// If x is not of the right length, SetUniformBytes returns nil and an error, -// and the receiver is unchanged. -// -// SetUniformBytes can be used to set s to a uniformly distributed value given -// 64 uniformly distributed random bytes. -func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) { - if len(x) != 64 { - return nil, errors.New("edwards25519: invalid SetUniformBytes input length") - } - - // We have a value x of 512 bits, but our fiatScalarFromBytes function - // expects an input lower than l, which is a little over 252 bits. - // - // Instead of writing a reduction function that operates on wider inputs, we - // can interpret x as the sum of three shorter values a, b, and c. - // - // x = a + b * 2^168 + c * 2^336 mod l - // - // We then precompute 2^168 and 2^336 modulo l, and perform the reduction - // with two multiplications and two additions. - - s.setShortBytes(x[:21]) - t := new(Scalar).setShortBytes(x[21:42]) - s.Add(s, t.Multiply(t, scalarTwo168)) - t.setShortBytes(x[42:]) - s.Add(s, t.Multiply(t, scalarTwo336)) - - return s, nil -} - -// scalarTwo168 and scalarTwo336 are 2^168 and 2^336 modulo l, encoded as a -// fiatScalarMontgomeryDomainFieldElement, which is a little-endian 4-limb value -// in the 2^256 Montgomery domain. -var scalarTwo168 = &Scalar{s: [4]uint64{0x5b8ab432eac74798, 0x38afddd6de59d5d7, - 0xa2c131b399411b7c, 0x6329a7ed9ce5a30}} -var scalarTwo336 = &Scalar{s: [4]uint64{0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b, - 0x63aa97a331b4f2ee, 0x3d217f5be65cb5c}} - -// setShortBytes sets s = x mod l, where x is a little-endian integer shorter -// than 32 bytes. -func (s *Scalar) setShortBytes(x []byte) *Scalar { - if len(x) >= 32 { - panic("edwards25519: internal error: setShortBytes called with a long string") - } - var buf [32]byte - copy(buf[:], x) - fiatScalarFromBytes((*[4]uint64)(&s.s), &buf) - fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s)) - return s -} - -// SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of -// s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes -// returns nil and an error, and the receiver is unchanged. -func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) { - if len(x) != 32 { - return nil, errors.New("invalid scalar length") - } - if !isReduced(x) { - return nil, errors.New("invalid scalar encoding") - } - - fiatScalarFromBytes((*[4]uint64)(&s.s), (*[32]byte)(x)) - fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s)) - - return s, nil -} - -// scalarMinusOneBytes is l - 1 in little endian. -var scalarMinusOneBytes = [32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16} - -// isReduced returns whether the given scalar in 32-byte little endian encoded -// form is reduced modulo l. -func isReduced(s []byte) bool { - if len(s) != 32 { - return false - } - - for i := len(s) - 1; i >= 0; i-- { - switch { - case s[i] > scalarMinusOneBytes[i]: - return false - case s[i] < scalarMinusOneBytes[i]: - return true - } - } - return true -} - -// SetBytesWithClamping applies the buffer pruning described in RFC 8032, -// Section 5.1.5 (also known as clamping) and sets s to the result. The input -// must be 32 bytes, and it is not modified. If x is not of the right length, -// SetBytesWithClamping returns nil and an error, and the receiver is unchanged. -// -// Note that since Scalar values are always reduced modulo the prime order of -// the curve, the resulting value will not preserve any of the cofactor-clearing -// properties that clamping is meant to provide. It will however work as -// expected as long as it is applied to points on the prime order subgroup, like -// in Ed25519. In fact, it is lost to history why RFC 8032 adopted the -// irrelevant RFC 7748 clamping, but it is now required for compatibility. -func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) { - // The description above omits the purpose of the high bits of the clamping - // for brevity, but those are also lost to reductions, and are also - // irrelevant to edwards25519 as they protect against a specific - // implementation bug that was once observed in a generic Montgomery ladder. - if len(x) != 32 { - return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length") - } - - // We need to use the wide reduction from SetUniformBytes, since clamping - // sets the 2^254 bit, making the value higher than the order. - var wideBytes [64]byte - copy(wideBytes[:], x[:]) - wideBytes[0] &= 248 - wideBytes[31] &= 63 - wideBytes[31] |= 64 - return s.SetUniformBytes(wideBytes[:]) -} - -// Bytes returns the canonical 32-byte little-endian encoding of s. -func (s *Scalar) Bytes() []byte { - // This function is outlined to make the allocations inline in the caller - // rather than happen on the heap. - var encoded [32]byte - return s.bytes(&encoded) -} - -func (s *Scalar) bytes(out *[32]byte) []byte { - var ss fiatScalarNonMontgomeryDomainFieldElement - fiatScalarFromMontgomery(&ss, &s.s) - fiatScalarToBytes(out, (*[4]uint64)(&ss)) - return out[:] -} - -// Equal returns 1 if s and t are equal, and 0 otherwise. -func (s *Scalar) Equal(t *Scalar) int { - var diff fiatScalarMontgomeryDomainFieldElement - fiatScalarSub(&diff, &s.s, &t.s) - var nonzero uint64 - fiatScalarNonzero(&nonzero, (*[4]uint64)(&diff)) - nonzero |= nonzero >> 32 - nonzero |= nonzero >> 16 - nonzero |= nonzero >> 8 - nonzero |= nonzero >> 4 - nonzero |= nonzero >> 2 - nonzero |= nonzero >> 1 - return int(^nonzero) & 1 -} - -// nonAdjacentForm computes a width-w non-adjacent form for this scalar. -// -// w must be between 2 and 8, or nonAdjacentForm will panic. -func (s *Scalar) nonAdjacentForm(w uint) [256]int8 { - // This implementation is adapted from the one - // in curve25519-dalek and is documented there: - // https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871 - b := s.Bytes() - if b[31] > 127 { - panic("scalar has high bit set illegally") - } - if w < 2 { - panic("w must be at least 2 by the definition of NAF") - } else if w > 8 { - panic("NAF digits must fit in int8") - } - - var naf [256]int8 - var digits [5]uint64 - - for i := 0; i < 4; i++ { - digits[i] = binary.LittleEndian.Uint64(b[i*8:]) - } - - width := uint64(1 << w) - windowMask := uint64(width - 1) - - pos := uint(0) - carry := uint64(0) - for pos < 256 { - indexU64 := pos / 64 - indexBit := pos % 64 - var bitBuf uint64 - if indexBit < 64-w { - // This window's bits are contained in a single u64 - bitBuf = digits[indexU64] >> indexBit - } else { - // Combine the current 64 bits with bits from the next 64 - bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit)) - } - - // Add carry into the current window - window := carry + (bitBuf & windowMask) - - if window&1 == 0 { - // If the window value is even, preserve the carry and continue. - // Why is the carry preserved? - // If carry == 0 and window & 1 == 0, - // then the next carry should be 0 - // If carry == 1 and window & 1 == 0, - // then bit_buf & 1 == 1 so the next carry should be 1 - pos += 1 - continue - } - - if window < width/2 { - carry = 0 - naf[pos] = int8(window) - } else { - carry = 1 - naf[pos] = int8(window) - int8(width) - } - - pos += w - } - return naf -} - -func (s *Scalar) signedRadix16() [64]int8 { - b := s.Bytes() - if b[31] > 127 { - panic("scalar has high bit set illegally") - } - - var digits [64]int8 - - // Compute unsigned radix-16 digits: - for i := 0; i < 32; i++ { - digits[2*i] = int8(b[i] & 15) - digits[2*i+1] = int8((b[i] >> 4) & 15) - } - - // Recenter coefficients: - for i := 0; i < 63; i++ { - carry := (digits[i] + 8) >> 4 - digits[i] -= carry << 4 - digits[i+1] += carry - } - - return digits -} diff --git a/vendor/filippo.io/edwards25519/scalar_fiat.go b/vendor/filippo.io/edwards25519/scalar_fiat.go deleted file mode 100644 index 2e5782b..0000000 --- a/vendor/filippo.io/edwards25519/scalar_fiat.go +++ /dev/null @@ -1,1147 +0,0 @@ -// Code generated by Fiat Cryptography. DO NOT EDIT. -// -// Autogenerated: word_by_word_montgomery --lang Go --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name edwards25519 Scalar 64 '2^252 + 27742317777372353535851937790883648493' mul add sub opp nonzero from_montgomery to_montgomery to_bytes from_bytes -// -// curve description: Scalar -// -// machine_wordsize = 64 (from "64") -// -// requested operations: mul, add, sub, opp, nonzero, from_montgomery, to_montgomery, to_bytes, from_bytes -// -// m = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed (from "2^252 + 27742317777372353535851937790883648493") -// -// -// -// NOTE: In addition to the bounds specified above each function, all -// -// functions synthesized for this Montgomery arithmetic require the -// -// input to be strictly less than the prime modulus (m), and also -// -// require the input to be in the unique saturated representation. -// -// All functions also ensure that these two properties are true of -// -// return values. -// -// -// -// Computed values: -// -// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) -// -// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) -// -// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in -// -// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 - -package edwards25519 - -import "math/bits" - -type fiatScalarUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 -type fiatScalarInt1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 - -// The type fiatScalarMontgomeryDomainFieldElement is a field element in the Montgomery domain. -// -// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -type fiatScalarMontgomeryDomainFieldElement [4]uint64 - -// The type fiatScalarNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. -// -// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -type fiatScalarNonMontgomeryDomainFieldElement [4]uint64 - -// fiatScalarCmovznzU64 is a single-word conditional move. -// -// Postconditions: -// -// out1 = (if arg1 = 0 then arg2 else arg3) -// -// Input Bounds: -// -// arg1: [0x0 ~> 0x1] -// arg2: [0x0 ~> 0xffffffffffffffff] -// arg3: [0x0 ~> 0xffffffffffffffff] -// -// Output Bounds: -// -// out1: [0x0 ~> 0xffffffffffffffff] -func fiatScalarCmovznzU64(out1 *uint64, arg1 fiatScalarUint1, arg2 uint64, arg3 uint64) { - x1 := (uint64(arg1) * 0xffffffffffffffff) - x2 := ((x1 & arg3) | ((^x1) & arg2)) - *out1 = x2 -} - -// fiatScalarMul multiplies two field elements in the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// 0 ≤ eval arg2 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m -// 0 ≤ eval out1 < m -func fiatScalarMul(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) { - x1 := arg1[1] - x2 := arg1[2] - x3 := arg1[3] - x4 := arg1[0] - var x5 uint64 - var x6 uint64 - x6, x5 = bits.Mul64(x4, arg2[3]) - var x7 uint64 - var x8 uint64 - x8, x7 = bits.Mul64(x4, arg2[2]) - var x9 uint64 - var x10 uint64 - x10, x9 = bits.Mul64(x4, arg2[1]) - var x11 uint64 - var x12 uint64 - x12, x11 = bits.Mul64(x4, arg2[0]) - var x13 uint64 - var x14 uint64 - x13, x14 = bits.Add64(x12, x9, uint64(0x0)) - var x15 uint64 - var x16 uint64 - x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14))) - var x17 uint64 - var x18 uint64 - x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16))) - x19 := (uint64(fiatScalarUint1(x18)) + x6) - var x20 uint64 - _, x20 = bits.Mul64(x11, 0xd2b51da312547e1b) - var x22 uint64 - var x23 uint64 - x23, x22 = bits.Mul64(x20, 0x1000000000000000) - var x24 uint64 - var x25 uint64 - x25, x24 = bits.Mul64(x20, 0x14def9dea2f79cd6) - var x26 uint64 - var x27 uint64 - x27, x26 = bits.Mul64(x20, 0x5812631a5cf5d3ed) - var x28 uint64 - var x29 uint64 - x28, x29 = bits.Add64(x27, x24, uint64(0x0)) - x30 := (uint64(fiatScalarUint1(x29)) + x25) - var x32 uint64 - _, x32 = bits.Add64(x11, x26, uint64(0x0)) - var x33 uint64 - var x34 uint64 - x33, x34 = bits.Add64(x13, x28, uint64(fiatScalarUint1(x32))) - var x35 uint64 - var x36 uint64 - x35, x36 = bits.Add64(x15, x30, uint64(fiatScalarUint1(x34))) - var x37 uint64 - var x38 uint64 - x37, x38 = bits.Add64(x17, x22, uint64(fiatScalarUint1(x36))) - var x39 uint64 - var x40 uint64 - x39, x40 = bits.Add64(x19, x23, uint64(fiatScalarUint1(x38))) - var x41 uint64 - var x42 uint64 - x42, x41 = bits.Mul64(x1, arg2[3]) - var x43 uint64 - var x44 uint64 - x44, x43 = bits.Mul64(x1, arg2[2]) - var x45 uint64 - var x46 uint64 - x46, x45 = bits.Mul64(x1, arg2[1]) - var x47 uint64 - var x48 uint64 - x48, x47 = bits.Mul64(x1, arg2[0]) - var x49 uint64 - var x50 uint64 - x49, x50 = bits.Add64(x48, x45, uint64(0x0)) - var x51 uint64 - var x52 uint64 - x51, x52 = bits.Add64(x46, x43, uint64(fiatScalarUint1(x50))) - var x53 uint64 - var x54 uint64 - x53, x54 = bits.Add64(x44, x41, uint64(fiatScalarUint1(x52))) - x55 := (uint64(fiatScalarUint1(x54)) + x42) - var x56 uint64 - var x57 uint64 - x56, x57 = bits.Add64(x33, x47, uint64(0x0)) - var x58 uint64 - var x59 uint64 - x58, x59 = bits.Add64(x35, x49, uint64(fiatScalarUint1(x57))) - var x60 uint64 - var x61 uint64 - x60, x61 = bits.Add64(x37, x51, uint64(fiatScalarUint1(x59))) - var x62 uint64 - var x63 uint64 - x62, x63 = bits.Add64(x39, x53, uint64(fiatScalarUint1(x61))) - var x64 uint64 - var x65 uint64 - x64, x65 = bits.Add64(uint64(fiatScalarUint1(x40)), x55, uint64(fiatScalarUint1(x63))) - var x66 uint64 - _, x66 = bits.Mul64(x56, 0xd2b51da312547e1b) - var x68 uint64 - var x69 uint64 - x69, x68 = bits.Mul64(x66, 0x1000000000000000) - var x70 uint64 - var x71 uint64 - x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6) - var x72 uint64 - var x73 uint64 - x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed) - var x74 uint64 - var x75 uint64 - x74, x75 = bits.Add64(x73, x70, uint64(0x0)) - x76 := (uint64(fiatScalarUint1(x75)) + x71) - var x78 uint64 - _, x78 = bits.Add64(x56, x72, uint64(0x0)) - var x79 uint64 - var x80 uint64 - x79, x80 = bits.Add64(x58, x74, uint64(fiatScalarUint1(x78))) - var x81 uint64 - var x82 uint64 - x81, x82 = bits.Add64(x60, x76, uint64(fiatScalarUint1(x80))) - var x83 uint64 - var x84 uint64 - x83, x84 = bits.Add64(x62, x68, uint64(fiatScalarUint1(x82))) - var x85 uint64 - var x86 uint64 - x85, x86 = bits.Add64(x64, x69, uint64(fiatScalarUint1(x84))) - x87 := (uint64(fiatScalarUint1(x86)) + uint64(fiatScalarUint1(x65))) - var x88 uint64 - var x89 uint64 - x89, x88 = bits.Mul64(x2, arg2[3]) - var x90 uint64 - var x91 uint64 - x91, x90 = bits.Mul64(x2, arg2[2]) - var x92 uint64 - var x93 uint64 - x93, x92 = bits.Mul64(x2, arg2[1]) - var x94 uint64 - var x95 uint64 - x95, x94 = bits.Mul64(x2, arg2[0]) - var x96 uint64 - var x97 uint64 - x96, x97 = bits.Add64(x95, x92, uint64(0x0)) - var x98 uint64 - var x99 uint64 - x98, x99 = bits.Add64(x93, x90, uint64(fiatScalarUint1(x97))) - var x100 uint64 - var x101 uint64 - x100, x101 = bits.Add64(x91, x88, uint64(fiatScalarUint1(x99))) - x102 := (uint64(fiatScalarUint1(x101)) + x89) - var x103 uint64 - var x104 uint64 - x103, x104 = bits.Add64(x79, x94, uint64(0x0)) - var x105 uint64 - var x106 uint64 - x105, x106 = bits.Add64(x81, x96, uint64(fiatScalarUint1(x104))) - var x107 uint64 - var x108 uint64 - x107, x108 = bits.Add64(x83, x98, uint64(fiatScalarUint1(x106))) - var x109 uint64 - var x110 uint64 - x109, x110 = bits.Add64(x85, x100, uint64(fiatScalarUint1(x108))) - var x111 uint64 - var x112 uint64 - x111, x112 = bits.Add64(x87, x102, uint64(fiatScalarUint1(x110))) - var x113 uint64 - _, x113 = bits.Mul64(x103, 0xd2b51da312547e1b) - var x115 uint64 - var x116 uint64 - x116, x115 = bits.Mul64(x113, 0x1000000000000000) - var x117 uint64 - var x118 uint64 - x118, x117 = bits.Mul64(x113, 0x14def9dea2f79cd6) - var x119 uint64 - var x120 uint64 - x120, x119 = bits.Mul64(x113, 0x5812631a5cf5d3ed) - var x121 uint64 - var x122 uint64 - x121, x122 = bits.Add64(x120, x117, uint64(0x0)) - x123 := (uint64(fiatScalarUint1(x122)) + x118) - var x125 uint64 - _, x125 = bits.Add64(x103, x119, uint64(0x0)) - var x126 uint64 - var x127 uint64 - x126, x127 = bits.Add64(x105, x121, uint64(fiatScalarUint1(x125))) - var x128 uint64 - var x129 uint64 - x128, x129 = bits.Add64(x107, x123, uint64(fiatScalarUint1(x127))) - var x130 uint64 - var x131 uint64 - x130, x131 = bits.Add64(x109, x115, uint64(fiatScalarUint1(x129))) - var x132 uint64 - var x133 uint64 - x132, x133 = bits.Add64(x111, x116, uint64(fiatScalarUint1(x131))) - x134 := (uint64(fiatScalarUint1(x133)) + uint64(fiatScalarUint1(x112))) - var x135 uint64 - var x136 uint64 - x136, x135 = bits.Mul64(x3, arg2[3]) - var x137 uint64 - var x138 uint64 - x138, x137 = bits.Mul64(x3, arg2[2]) - var x139 uint64 - var x140 uint64 - x140, x139 = bits.Mul64(x3, arg2[1]) - var x141 uint64 - var x142 uint64 - x142, x141 = bits.Mul64(x3, arg2[0]) - var x143 uint64 - var x144 uint64 - x143, x144 = bits.Add64(x142, x139, uint64(0x0)) - var x145 uint64 - var x146 uint64 - x145, x146 = bits.Add64(x140, x137, uint64(fiatScalarUint1(x144))) - var x147 uint64 - var x148 uint64 - x147, x148 = bits.Add64(x138, x135, uint64(fiatScalarUint1(x146))) - x149 := (uint64(fiatScalarUint1(x148)) + x136) - var x150 uint64 - var x151 uint64 - x150, x151 = bits.Add64(x126, x141, uint64(0x0)) - var x152 uint64 - var x153 uint64 - x152, x153 = bits.Add64(x128, x143, uint64(fiatScalarUint1(x151))) - var x154 uint64 - var x155 uint64 - x154, x155 = bits.Add64(x130, x145, uint64(fiatScalarUint1(x153))) - var x156 uint64 - var x157 uint64 - x156, x157 = bits.Add64(x132, x147, uint64(fiatScalarUint1(x155))) - var x158 uint64 - var x159 uint64 - x158, x159 = bits.Add64(x134, x149, uint64(fiatScalarUint1(x157))) - var x160 uint64 - _, x160 = bits.Mul64(x150, 0xd2b51da312547e1b) - var x162 uint64 - var x163 uint64 - x163, x162 = bits.Mul64(x160, 0x1000000000000000) - var x164 uint64 - var x165 uint64 - x165, x164 = bits.Mul64(x160, 0x14def9dea2f79cd6) - var x166 uint64 - var x167 uint64 - x167, x166 = bits.Mul64(x160, 0x5812631a5cf5d3ed) - var x168 uint64 - var x169 uint64 - x168, x169 = bits.Add64(x167, x164, uint64(0x0)) - x170 := (uint64(fiatScalarUint1(x169)) + x165) - var x172 uint64 - _, x172 = bits.Add64(x150, x166, uint64(0x0)) - var x173 uint64 - var x174 uint64 - x173, x174 = bits.Add64(x152, x168, uint64(fiatScalarUint1(x172))) - var x175 uint64 - var x176 uint64 - x175, x176 = bits.Add64(x154, x170, uint64(fiatScalarUint1(x174))) - var x177 uint64 - var x178 uint64 - x177, x178 = bits.Add64(x156, x162, uint64(fiatScalarUint1(x176))) - var x179 uint64 - var x180 uint64 - x179, x180 = bits.Add64(x158, x163, uint64(fiatScalarUint1(x178))) - x181 := (uint64(fiatScalarUint1(x180)) + uint64(fiatScalarUint1(x159))) - var x182 uint64 - var x183 uint64 - x182, x183 = bits.Sub64(x173, 0x5812631a5cf5d3ed, uint64(0x0)) - var x184 uint64 - var x185 uint64 - x184, x185 = bits.Sub64(x175, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x183))) - var x186 uint64 - var x187 uint64 - x186, x187 = bits.Sub64(x177, uint64(0x0), uint64(fiatScalarUint1(x185))) - var x188 uint64 - var x189 uint64 - x188, x189 = bits.Sub64(x179, 0x1000000000000000, uint64(fiatScalarUint1(x187))) - var x191 uint64 - _, x191 = bits.Sub64(x181, uint64(0x0), uint64(fiatScalarUint1(x189))) - var x192 uint64 - fiatScalarCmovznzU64(&x192, fiatScalarUint1(x191), x182, x173) - var x193 uint64 - fiatScalarCmovznzU64(&x193, fiatScalarUint1(x191), x184, x175) - var x194 uint64 - fiatScalarCmovznzU64(&x194, fiatScalarUint1(x191), x186, x177) - var x195 uint64 - fiatScalarCmovznzU64(&x195, fiatScalarUint1(x191), x188, x179) - out1[0] = x192 - out1[1] = x193 - out1[2] = x194 - out1[3] = x195 -} - -// fiatScalarAdd adds two field elements in the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// 0 ≤ eval arg2 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m -// 0 ≤ eval out1 < m -func fiatScalarAdd(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) { - var x1 uint64 - var x2 uint64 - x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0)) - var x3 uint64 - var x4 uint64 - x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2))) - var x5 uint64 - var x6 uint64 - x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4))) - var x7 uint64 - var x8 uint64 - x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6))) - var x9 uint64 - var x10 uint64 - x9, x10 = bits.Sub64(x1, 0x5812631a5cf5d3ed, uint64(0x0)) - var x11 uint64 - var x12 uint64 - x11, x12 = bits.Sub64(x3, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x10))) - var x13 uint64 - var x14 uint64 - x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(fiatScalarUint1(x12))) - var x15 uint64 - var x16 uint64 - x15, x16 = bits.Sub64(x7, 0x1000000000000000, uint64(fiatScalarUint1(x14))) - var x18 uint64 - _, x18 = bits.Sub64(uint64(fiatScalarUint1(x8)), uint64(0x0), uint64(fiatScalarUint1(x16))) - var x19 uint64 - fiatScalarCmovznzU64(&x19, fiatScalarUint1(x18), x9, x1) - var x20 uint64 - fiatScalarCmovznzU64(&x20, fiatScalarUint1(x18), x11, x3) - var x21 uint64 - fiatScalarCmovznzU64(&x21, fiatScalarUint1(x18), x13, x5) - var x22 uint64 - fiatScalarCmovznzU64(&x22, fiatScalarUint1(x18), x15, x7) - out1[0] = x19 - out1[1] = x20 - out1[2] = x21 - out1[3] = x22 -} - -// fiatScalarSub subtracts two field elements in the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// 0 ≤ eval arg2 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m -// 0 ≤ eval out1 < m -func fiatScalarSub(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) { - var x1 uint64 - var x2 uint64 - x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0)) - var x3 uint64 - var x4 uint64 - x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2))) - var x5 uint64 - var x6 uint64 - x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4))) - var x7 uint64 - var x8 uint64 - x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6))) - var x9 uint64 - fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff) - var x10 uint64 - var x11 uint64 - x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0)) - var x12 uint64 - var x13 uint64 - x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11))) - var x14 uint64 - var x15 uint64 - x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13))) - var x16 uint64 - x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15))) - out1[0] = x10 - out1[1] = x12 - out1[2] = x14 - out1[3] = x16 -} - -// fiatScalarOpp negates a field element in the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m -// 0 ≤ eval out1 < m -func fiatScalarOpp(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) { - var x1 uint64 - var x2 uint64 - x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0)) - var x3 uint64 - var x4 uint64 - x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(fiatScalarUint1(x2))) - var x5 uint64 - var x6 uint64 - x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(fiatScalarUint1(x4))) - var x7 uint64 - var x8 uint64 - x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(fiatScalarUint1(x6))) - var x9 uint64 - fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff) - var x10 uint64 - var x11 uint64 - x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0)) - var x12 uint64 - var x13 uint64 - x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11))) - var x14 uint64 - var x15 uint64 - x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13))) - var x16 uint64 - x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15))) - out1[0] = x10 - out1[1] = x12 - out1[2] = x14 - out1[3] = x16 -} - -// fiatScalarNonzero outputs a single non-zero word if the input is non-zero and zero otherwise. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0 -// -// Input Bounds: -// -// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] -// -// Output Bounds: -// -// out1: [0x0 ~> 0xffffffffffffffff] -func fiatScalarNonzero(out1 *uint64, arg1 *[4]uint64) { - x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))) - *out1 = x1 -} - -// fiatScalarFromMontgomery translates a field element out of the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m -// 0 ≤ eval out1 < m -func fiatScalarFromMontgomery(out1 *fiatScalarNonMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) { - x1 := arg1[0] - var x2 uint64 - _, x2 = bits.Mul64(x1, 0xd2b51da312547e1b) - var x4 uint64 - var x5 uint64 - x5, x4 = bits.Mul64(x2, 0x1000000000000000) - var x6 uint64 - var x7 uint64 - x7, x6 = bits.Mul64(x2, 0x14def9dea2f79cd6) - var x8 uint64 - var x9 uint64 - x9, x8 = bits.Mul64(x2, 0x5812631a5cf5d3ed) - var x10 uint64 - var x11 uint64 - x10, x11 = bits.Add64(x9, x6, uint64(0x0)) - var x13 uint64 - _, x13 = bits.Add64(x1, x8, uint64(0x0)) - var x14 uint64 - var x15 uint64 - x14, x15 = bits.Add64(uint64(0x0), x10, uint64(fiatScalarUint1(x13))) - var x16 uint64 - var x17 uint64 - x16, x17 = bits.Add64(x14, arg1[1], uint64(0x0)) - var x18 uint64 - _, x18 = bits.Mul64(x16, 0xd2b51da312547e1b) - var x20 uint64 - var x21 uint64 - x21, x20 = bits.Mul64(x18, 0x1000000000000000) - var x22 uint64 - var x23 uint64 - x23, x22 = bits.Mul64(x18, 0x14def9dea2f79cd6) - var x24 uint64 - var x25 uint64 - x25, x24 = bits.Mul64(x18, 0x5812631a5cf5d3ed) - var x26 uint64 - var x27 uint64 - x26, x27 = bits.Add64(x25, x22, uint64(0x0)) - var x29 uint64 - _, x29 = bits.Add64(x16, x24, uint64(0x0)) - var x30 uint64 - var x31 uint64 - x30, x31 = bits.Add64((uint64(fiatScalarUint1(x17)) + (uint64(fiatScalarUint1(x15)) + (uint64(fiatScalarUint1(x11)) + x7))), x26, uint64(fiatScalarUint1(x29))) - var x32 uint64 - var x33 uint64 - x32, x33 = bits.Add64(x4, (uint64(fiatScalarUint1(x27)) + x23), uint64(fiatScalarUint1(x31))) - var x34 uint64 - var x35 uint64 - x34, x35 = bits.Add64(x5, x20, uint64(fiatScalarUint1(x33))) - var x36 uint64 - var x37 uint64 - x36, x37 = bits.Add64(x30, arg1[2], uint64(0x0)) - var x38 uint64 - var x39 uint64 - x38, x39 = bits.Add64(x32, uint64(0x0), uint64(fiatScalarUint1(x37))) - var x40 uint64 - var x41 uint64 - x40, x41 = bits.Add64(x34, uint64(0x0), uint64(fiatScalarUint1(x39))) - var x42 uint64 - _, x42 = bits.Mul64(x36, 0xd2b51da312547e1b) - var x44 uint64 - var x45 uint64 - x45, x44 = bits.Mul64(x42, 0x1000000000000000) - var x46 uint64 - var x47 uint64 - x47, x46 = bits.Mul64(x42, 0x14def9dea2f79cd6) - var x48 uint64 - var x49 uint64 - x49, x48 = bits.Mul64(x42, 0x5812631a5cf5d3ed) - var x50 uint64 - var x51 uint64 - x50, x51 = bits.Add64(x49, x46, uint64(0x0)) - var x53 uint64 - _, x53 = bits.Add64(x36, x48, uint64(0x0)) - var x54 uint64 - var x55 uint64 - x54, x55 = bits.Add64(x38, x50, uint64(fiatScalarUint1(x53))) - var x56 uint64 - var x57 uint64 - x56, x57 = bits.Add64(x40, (uint64(fiatScalarUint1(x51)) + x47), uint64(fiatScalarUint1(x55))) - var x58 uint64 - var x59 uint64 - x58, x59 = bits.Add64((uint64(fiatScalarUint1(x41)) + (uint64(fiatScalarUint1(x35)) + x21)), x44, uint64(fiatScalarUint1(x57))) - var x60 uint64 - var x61 uint64 - x60, x61 = bits.Add64(x54, arg1[3], uint64(0x0)) - var x62 uint64 - var x63 uint64 - x62, x63 = bits.Add64(x56, uint64(0x0), uint64(fiatScalarUint1(x61))) - var x64 uint64 - var x65 uint64 - x64, x65 = bits.Add64(x58, uint64(0x0), uint64(fiatScalarUint1(x63))) - var x66 uint64 - _, x66 = bits.Mul64(x60, 0xd2b51da312547e1b) - var x68 uint64 - var x69 uint64 - x69, x68 = bits.Mul64(x66, 0x1000000000000000) - var x70 uint64 - var x71 uint64 - x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6) - var x72 uint64 - var x73 uint64 - x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed) - var x74 uint64 - var x75 uint64 - x74, x75 = bits.Add64(x73, x70, uint64(0x0)) - var x77 uint64 - _, x77 = bits.Add64(x60, x72, uint64(0x0)) - var x78 uint64 - var x79 uint64 - x78, x79 = bits.Add64(x62, x74, uint64(fiatScalarUint1(x77))) - var x80 uint64 - var x81 uint64 - x80, x81 = bits.Add64(x64, (uint64(fiatScalarUint1(x75)) + x71), uint64(fiatScalarUint1(x79))) - var x82 uint64 - var x83 uint64 - x82, x83 = bits.Add64((uint64(fiatScalarUint1(x65)) + (uint64(fiatScalarUint1(x59)) + x45)), x68, uint64(fiatScalarUint1(x81))) - x84 := (uint64(fiatScalarUint1(x83)) + x69) - var x85 uint64 - var x86 uint64 - x85, x86 = bits.Sub64(x78, 0x5812631a5cf5d3ed, uint64(0x0)) - var x87 uint64 - var x88 uint64 - x87, x88 = bits.Sub64(x80, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x86))) - var x89 uint64 - var x90 uint64 - x89, x90 = bits.Sub64(x82, uint64(0x0), uint64(fiatScalarUint1(x88))) - var x91 uint64 - var x92 uint64 - x91, x92 = bits.Sub64(x84, 0x1000000000000000, uint64(fiatScalarUint1(x90))) - var x94 uint64 - _, x94 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x92))) - var x95 uint64 - fiatScalarCmovznzU64(&x95, fiatScalarUint1(x94), x85, x78) - var x96 uint64 - fiatScalarCmovznzU64(&x96, fiatScalarUint1(x94), x87, x80) - var x97 uint64 - fiatScalarCmovznzU64(&x97, fiatScalarUint1(x94), x89, x82) - var x98 uint64 - fiatScalarCmovznzU64(&x98, fiatScalarUint1(x94), x91, x84) - out1[0] = x95 - out1[1] = x96 - out1[2] = x97 - out1[3] = x98 -} - -// fiatScalarToMontgomery translates a field element into the Montgomery domain. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// eval (from_montgomery out1) mod m = eval arg1 mod m -// 0 ≤ eval out1 < m -func fiatScalarToMontgomery(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarNonMontgomeryDomainFieldElement) { - x1 := arg1[1] - x2 := arg1[2] - x3 := arg1[3] - x4 := arg1[0] - var x5 uint64 - var x6 uint64 - x6, x5 = bits.Mul64(x4, 0x399411b7c309a3d) - var x7 uint64 - var x8 uint64 - x8, x7 = bits.Mul64(x4, 0xceec73d217f5be65) - var x9 uint64 - var x10 uint64 - x10, x9 = bits.Mul64(x4, 0xd00e1ba768859347) - var x11 uint64 - var x12 uint64 - x12, x11 = bits.Mul64(x4, 0xa40611e3449c0f01) - var x13 uint64 - var x14 uint64 - x13, x14 = bits.Add64(x12, x9, uint64(0x0)) - var x15 uint64 - var x16 uint64 - x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14))) - var x17 uint64 - var x18 uint64 - x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16))) - var x19 uint64 - _, x19 = bits.Mul64(x11, 0xd2b51da312547e1b) - var x21 uint64 - var x22 uint64 - x22, x21 = bits.Mul64(x19, 0x1000000000000000) - var x23 uint64 - var x24 uint64 - x24, x23 = bits.Mul64(x19, 0x14def9dea2f79cd6) - var x25 uint64 - var x26 uint64 - x26, x25 = bits.Mul64(x19, 0x5812631a5cf5d3ed) - var x27 uint64 - var x28 uint64 - x27, x28 = bits.Add64(x26, x23, uint64(0x0)) - var x30 uint64 - _, x30 = bits.Add64(x11, x25, uint64(0x0)) - var x31 uint64 - var x32 uint64 - x31, x32 = bits.Add64(x13, x27, uint64(fiatScalarUint1(x30))) - var x33 uint64 - var x34 uint64 - x33, x34 = bits.Add64(x15, (uint64(fiatScalarUint1(x28)) + x24), uint64(fiatScalarUint1(x32))) - var x35 uint64 - var x36 uint64 - x35, x36 = bits.Add64(x17, x21, uint64(fiatScalarUint1(x34))) - var x37 uint64 - var x38 uint64 - x38, x37 = bits.Mul64(x1, 0x399411b7c309a3d) - var x39 uint64 - var x40 uint64 - x40, x39 = bits.Mul64(x1, 0xceec73d217f5be65) - var x41 uint64 - var x42 uint64 - x42, x41 = bits.Mul64(x1, 0xd00e1ba768859347) - var x43 uint64 - var x44 uint64 - x44, x43 = bits.Mul64(x1, 0xa40611e3449c0f01) - var x45 uint64 - var x46 uint64 - x45, x46 = bits.Add64(x44, x41, uint64(0x0)) - var x47 uint64 - var x48 uint64 - x47, x48 = bits.Add64(x42, x39, uint64(fiatScalarUint1(x46))) - var x49 uint64 - var x50 uint64 - x49, x50 = bits.Add64(x40, x37, uint64(fiatScalarUint1(x48))) - var x51 uint64 - var x52 uint64 - x51, x52 = bits.Add64(x31, x43, uint64(0x0)) - var x53 uint64 - var x54 uint64 - x53, x54 = bits.Add64(x33, x45, uint64(fiatScalarUint1(x52))) - var x55 uint64 - var x56 uint64 - x55, x56 = bits.Add64(x35, x47, uint64(fiatScalarUint1(x54))) - var x57 uint64 - var x58 uint64 - x57, x58 = bits.Add64(((uint64(fiatScalarUint1(x36)) + (uint64(fiatScalarUint1(x18)) + x6)) + x22), x49, uint64(fiatScalarUint1(x56))) - var x59 uint64 - _, x59 = bits.Mul64(x51, 0xd2b51da312547e1b) - var x61 uint64 - var x62 uint64 - x62, x61 = bits.Mul64(x59, 0x1000000000000000) - var x63 uint64 - var x64 uint64 - x64, x63 = bits.Mul64(x59, 0x14def9dea2f79cd6) - var x65 uint64 - var x66 uint64 - x66, x65 = bits.Mul64(x59, 0x5812631a5cf5d3ed) - var x67 uint64 - var x68 uint64 - x67, x68 = bits.Add64(x66, x63, uint64(0x0)) - var x70 uint64 - _, x70 = bits.Add64(x51, x65, uint64(0x0)) - var x71 uint64 - var x72 uint64 - x71, x72 = bits.Add64(x53, x67, uint64(fiatScalarUint1(x70))) - var x73 uint64 - var x74 uint64 - x73, x74 = bits.Add64(x55, (uint64(fiatScalarUint1(x68)) + x64), uint64(fiatScalarUint1(x72))) - var x75 uint64 - var x76 uint64 - x75, x76 = bits.Add64(x57, x61, uint64(fiatScalarUint1(x74))) - var x77 uint64 - var x78 uint64 - x78, x77 = bits.Mul64(x2, 0x399411b7c309a3d) - var x79 uint64 - var x80 uint64 - x80, x79 = bits.Mul64(x2, 0xceec73d217f5be65) - var x81 uint64 - var x82 uint64 - x82, x81 = bits.Mul64(x2, 0xd00e1ba768859347) - var x83 uint64 - var x84 uint64 - x84, x83 = bits.Mul64(x2, 0xa40611e3449c0f01) - var x85 uint64 - var x86 uint64 - x85, x86 = bits.Add64(x84, x81, uint64(0x0)) - var x87 uint64 - var x88 uint64 - x87, x88 = bits.Add64(x82, x79, uint64(fiatScalarUint1(x86))) - var x89 uint64 - var x90 uint64 - x89, x90 = bits.Add64(x80, x77, uint64(fiatScalarUint1(x88))) - var x91 uint64 - var x92 uint64 - x91, x92 = bits.Add64(x71, x83, uint64(0x0)) - var x93 uint64 - var x94 uint64 - x93, x94 = bits.Add64(x73, x85, uint64(fiatScalarUint1(x92))) - var x95 uint64 - var x96 uint64 - x95, x96 = bits.Add64(x75, x87, uint64(fiatScalarUint1(x94))) - var x97 uint64 - var x98 uint64 - x97, x98 = bits.Add64(((uint64(fiatScalarUint1(x76)) + (uint64(fiatScalarUint1(x58)) + (uint64(fiatScalarUint1(x50)) + x38))) + x62), x89, uint64(fiatScalarUint1(x96))) - var x99 uint64 - _, x99 = bits.Mul64(x91, 0xd2b51da312547e1b) - var x101 uint64 - var x102 uint64 - x102, x101 = bits.Mul64(x99, 0x1000000000000000) - var x103 uint64 - var x104 uint64 - x104, x103 = bits.Mul64(x99, 0x14def9dea2f79cd6) - var x105 uint64 - var x106 uint64 - x106, x105 = bits.Mul64(x99, 0x5812631a5cf5d3ed) - var x107 uint64 - var x108 uint64 - x107, x108 = bits.Add64(x106, x103, uint64(0x0)) - var x110 uint64 - _, x110 = bits.Add64(x91, x105, uint64(0x0)) - var x111 uint64 - var x112 uint64 - x111, x112 = bits.Add64(x93, x107, uint64(fiatScalarUint1(x110))) - var x113 uint64 - var x114 uint64 - x113, x114 = bits.Add64(x95, (uint64(fiatScalarUint1(x108)) + x104), uint64(fiatScalarUint1(x112))) - var x115 uint64 - var x116 uint64 - x115, x116 = bits.Add64(x97, x101, uint64(fiatScalarUint1(x114))) - var x117 uint64 - var x118 uint64 - x118, x117 = bits.Mul64(x3, 0x399411b7c309a3d) - var x119 uint64 - var x120 uint64 - x120, x119 = bits.Mul64(x3, 0xceec73d217f5be65) - var x121 uint64 - var x122 uint64 - x122, x121 = bits.Mul64(x3, 0xd00e1ba768859347) - var x123 uint64 - var x124 uint64 - x124, x123 = bits.Mul64(x3, 0xa40611e3449c0f01) - var x125 uint64 - var x126 uint64 - x125, x126 = bits.Add64(x124, x121, uint64(0x0)) - var x127 uint64 - var x128 uint64 - x127, x128 = bits.Add64(x122, x119, uint64(fiatScalarUint1(x126))) - var x129 uint64 - var x130 uint64 - x129, x130 = bits.Add64(x120, x117, uint64(fiatScalarUint1(x128))) - var x131 uint64 - var x132 uint64 - x131, x132 = bits.Add64(x111, x123, uint64(0x0)) - var x133 uint64 - var x134 uint64 - x133, x134 = bits.Add64(x113, x125, uint64(fiatScalarUint1(x132))) - var x135 uint64 - var x136 uint64 - x135, x136 = bits.Add64(x115, x127, uint64(fiatScalarUint1(x134))) - var x137 uint64 - var x138 uint64 - x137, x138 = bits.Add64(((uint64(fiatScalarUint1(x116)) + (uint64(fiatScalarUint1(x98)) + (uint64(fiatScalarUint1(x90)) + x78))) + x102), x129, uint64(fiatScalarUint1(x136))) - var x139 uint64 - _, x139 = bits.Mul64(x131, 0xd2b51da312547e1b) - var x141 uint64 - var x142 uint64 - x142, x141 = bits.Mul64(x139, 0x1000000000000000) - var x143 uint64 - var x144 uint64 - x144, x143 = bits.Mul64(x139, 0x14def9dea2f79cd6) - var x145 uint64 - var x146 uint64 - x146, x145 = bits.Mul64(x139, 0x5812631a5cf5d3ed) - var x147 uint64 - var x148 uint64 - x147, x148 = bits.Add64(x146, x143, uint64(0x0)) - var x150 uint64 - _, x150 = bits.Add64(x131, x145, uint64(0x0)) - var x151 uint64 - var x152 uint64 - x151, x152 = bits.Add64(x133, x147, uint64(fiatScalarUint1(x150))) - var x153 uint64 - var x154 uint64 - x153, x154 = bits.Add64(x135, (uint64(fiatScalarUint1(x148)) + x144), uint64(fiatScalarUint1(x152))) - var x155 uint64 - var x156 uint64 - x155, x156 = bits.Add64(x137, x141, uint64(fiatScalarUint1(x154))) - x157 := ((uint64(fiatScalarUint1(x156)) + (uint64(fiatScalarUint1(x138)) + (uint64(fiatScalarUint1(x130)) + x118))) + x142) - var x158 uint64 - var x159 uint64 - x158, x159 = bits.Sub64(x151, 0x5812631a5cf5d3ed, uint64(0x0)) - var x160 uint64 - var x161 uint64 - x160, x161 = bits.Sub64(x153, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x159))) - var x162 uint64 - var x163 uint64 - x162, x163 = bits.Sub64(x155, uint64(0x0), uint64(fiatScalarUint1(x161))) - var x164 uint64 - var x165 uint64 - x164, x165 = bits.Sub64(x157, 0x1000000000000000, uint64(fiatScalarUint1(x163))) - var x167 uint64 - _, x167 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x165))) - var x168 uint64 - fiatScalarCmovznzU64(&x168, fiatScalarUint1(x167), x158, x151) - var x169 uint64 - fiatScalarCmovznzU64(&x169, fiatScalarUint1(x167), x160, x153) - var x170 uint64 - fiatScalarCmovznzU64(&x170, fiatScalarUint1(x167), x162, x155) - var x171 uint64 - fiatScalarCmovznzU64(&x171, fiatScalarUint1(x167), x164, x157) - out1[0] = x168 - out1[1] = x169 - out1[2] = x170 - out1[3] = x171 -} - -// fiatScalarToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. -// -// Preconditions: -// -// 0 ≤ eval arg1 < m -// -// Postconditions: -// -// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] -// -// Input Bounds: -// -// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]] -// -// Output Bounds: -// -// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]] -func fiatScalarToBytes(out1 *[32]uint8, arg1 *[4]uint64) { - x1 := arg1[3] - x2 := arg1[2] - x3 := arg1[1] - x4 := arg1[0] - x5 := (uint8(x4) & 0xff) - x6 := (x4 >> 8) - x7 := (uint8(x6) & 0xff) - x8 := (x6 >> 8) - x9 := (uint8(x8) & 0xff) - x10 := (x8 >> 8) - x11 := (uint8(x10) & 0xff) - x12 := (x10 >> 8) - x13 := (uint8(x12) & 0xff) - x14 := (x12 >> 8) - x15 := (uint8(x14) & 0xff) - x16 := (x14 >> 8) - x17 := (uint8(x16) & 0xff) - x18 := uint8((x16 >> 8)) - x19 := (uint8(x3) & 0xff) - x20 := (x3 >> 8) - x21 := (uint8(x20) & 0xff) - x22 := (x20 >> 8) - x23 := (uint8(x22) & 0xff) - x24 := (x22 >> 8) - x25 := (uint8(x24) & 0xff) - x26 := (x24 >> 8) - x27 := (uint8(x26) & 0xff) - x28 := (x26 >> 8) - x29 := (uint8(x28) & 0xff) - x30 := (x28 >> 8) - x31 := (uint8(x30) & 0xff) - x32 := uint8((x30 >> 8)) - x33 := (uint8(x2) & 0xff) - x34 := (x2 >> 8) - x35 := (uint8(x34) & 0xff) - x36 := (x34 >> 8) - x37 := (uint8(x36) & 0xff) - x38 := (x36 >> 8) - x39 := (uint8(x38) & 0xff) - x40 := (x38 >> 8) - x41 := (uint8(x40) & 0xff) - x42 := (x40 >> 8) - x43 := (uint8(x42) & 0xff) - x44 := (x42 >> 8) - x45 := (uint8(x44) & 0xff) - x46 := uint8((x44 >> 8)) - x47 := (uint8(x1) & 0xff) - x48 := (x1 >> 8) - x49 := (uint8(x48) & 0xff) - x50 := (x48 >> 8) - x51 := (uint8(x50) & 0xff) - x52 := (x50 >> 8) - x53 := (uint8(x52) & 0xff) - x54 := (x52 >> 8) - x55 := (uint8(x54) & 0xff) - x56 := (x54 >> 8) - x57 := (uint8(x56) & 0xff) - x58 := (x56 >> 8) - x59 := (uint8(x58) & 0xff) - x60 := uint8((x58 >> 8)) - out1[0] = x5 - out1[1] = x7 - out1[2] = x9 - out1[3] = x11 - out1[4] = x13 - out1[5] = x15 - out1[6] = x17 - out1[7] = x18 - out1[8] = x19 - out1[9] = x21 - out1[10] = x23 - out1[11] = x25 - out1[12] = x27 - out1[13] = x29 - out1[14] = x31 - out1[15] = x32 - out1[16] = x33 - out1[17] = x35 - out1[18] = x37 - out1[19] = x39 - out1[20] = x41 - out1[21] = x43 - out1[22] = x45 - out1[23] = x46 - out1[24] = x47 - out1[25] = x49 - out1[26] = x51 - out1[27] = x53 - out1[28] = x55 - out1[29] = x57 - out1[30] = x59 - out1[31] = x60 -} - -// fiatScalarFromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. -// -// Preconditions: -// -// 0 ≤ bytes_eval arg1 < m -// -// Postconditions: -// -// eval out1 mod m = bytes_eval arg1 mod m -// 0 ≤ eval out1 < m -// -// Input Bounds: -// -// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]] -// -// Output Bounds: -// -// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]] -func fiatScalarFromBytes(out1 *[4]uint64, arg1 *[32]uint8) { - x1 := (uint64(arg1[31]) << 56) - x2 := (uint64(arg1[30]) << 48) - x3 := (uint64(arg1[29]) << 40) - x4 := (uint64(arg1[28]) << 32) - x5 := (uint64(arg1[27]) << 24) - x6 := (uint64(arg1[26]) << 16) - x7 := (uint64(arg1[25]) << 8) - x8 := arg1[24] - x9 := (uint64(arg1[23]) << 56) - x10 := (uint64(arg1[22]) << 48) - x11 := (uint64(arg1[21]) << 40) - x12 := (uint64(arg1[20]) << 32) - x13 := (uint64(arg1[19]) << 24) - x14 := (uint64(arg1[18]) << 16) - x15 := (uint64(arg1[17]) << 8) - x16 := arg1[16] - x17 := (uint64(arg1[15]) << 56) - x18 := (uint64(arg1[14]) << 48) - x19 := (uint64(arg1[13]) << 40) - x20 := (uint64(arg1[12]) << 32) - x21 := (uint64(arg1[11]) << 24) - x22 := (uint64(arg1[10]) << 16) - x23 := (uint64(arg1[9]) << 8) - x24 := arg1[8] - x25 := (uint64(arg1[7]) << 56) - x26 := (uint64(arg1[6]) << 48) - x27 := (uint64(arg1[5]) << 40) - x28 := (uint64(arg1[4]) << 32) - x29 := (uint64(arg1[3]) << 24) - x30 := (uint64(arg1[2]) << 16) - x31 := (uint64(arg1[1]) << 8) - x32 := arg1[0] - x33 := (x31 + uint64(x32)) - x34 := (x30 + x33) - x35 := (x29 + x34) - x36 := (x28 + x35) - x37 := (x27 + x36) - x38 := (x26 + x37) - x39 := (x25 + x38) - x40 := (x23 + uint64(x24)) - x41 := (x22 + x40) - x42 := (x21 + x41) - x43 := (x20 + x42) - x44 := (x19 + x43) - x45 := (x18 + x44) - x46 := (x17 + x45) - x47 := (x15 + uint64(x16)) - x48 := (x14 + x47) - x49 := (x13 + x48) - x50 := (x12 + x49) - x51 := (x11 + x50) - x52 := (x10 + x51) - x53 := (x9 + x52) - x54 := (x7 + uint64(x8)) - x55 := (x6 + x54) - x56 := (x5 + x55) - x57 := (x4 + x56) - x58 := (x3 + x57) - x59 := (x2 + x58) - x60 := (x1 + x59) - out1[0] = x39 - out1[1] = x46 - out1[2] = x53 - out1[3] = x60 -} diff --git a/vendor/filippo.io/edwards25519/scalarmult.go b/vendor/filippo.io/edwards25519/scalarmult.go deleted file mode 100644 index f7ca3ce..0000000 --- a/vendor/filippo.io/edwards25519/scalarmult.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package edwards25519 - -import "sync" - -// basepointTable is a set of 32 affineLookupTables, where table i is generated -// from 256i * basepoint. It is precomputed the first time it's used. -func basepointTable() *[32]affineLookupTable { - basepointTablePrecomp.initOnce.Do(func() { - p := NewGeneratorPoint() - for i := 0; i < 32; i++ { - basepointTablePrecomp.table[i].FromP3(p) - for j := 0; j < 8; j++ { - p.Add(p, p) - } - } - }) - return &basepointTablePrecomp.table -} - -var basepointTablePrecomp struct { - table [32]affineLookupTable - initOnce sync.Once -} - -// ScalarBaseMult sets v = x * B, where B is the canonical generator, and -// returns v. -// -// The scalar multiplication is done in constant time. -func (v *Point) ScalarBaseMult(x *Scalar) *Point { - basepointTable := basepointTable() - - // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i ) - // as described in the Ed25519 paper - // - // Group even and odd coefficients - // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B - // + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B - // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B - // + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B) - // - // We use a lookup table for each i to get x_i*16^(2*i)*B - // and do four doublings to multiply by 16. - digits := x.signedRadix16() - - multiple := &affineCached{} - tmp1 := &projP1xP1{} - tmp2 := &projP2{} - - // Accumulate the odd components first - v.Set(NewIdentityPoint()) - for i := 1; i < 64; i += 2 { - basepointTable[i/2].SelectInto(multiple, digits[i]) - tmp1.AddAffine(v, multiple) - v.fromP1xP1(tmp1) - } - - // Multiply by 16 - tmp2.FromP3(v) // tmp2 = v in P2 coords - tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords - tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords - tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords - tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords - v.fromP1xP1(tmp1) // now v = 16*(odd components) - - // Accumulate the even components - for i := 0; i < 64; i += 2 { - basepointTable[i/2].SelectInto(multiple, digits[i]) - tmp1.AddAffine(v, multiple) - v.fromP1xP1(tmp1) - } - - return v -} - -// ScalarMult sets v = x * q, and returns v. -// -// The scalar multiplication is done in constant time. -func (v *Point) ScalarMult(x *Scalar, q *Point) *Point { - checkInitialized(q) - - var table projLookupTable - table.FromP3(q) - - // Write x = sum(x_i * 16^i) - // so x*Q = sum( Q*x_i*16^i ) - // = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... ) - // <------compute inside out--------- - // - // We use the lookup table to get the x_i*Q values - // and do four doublings to compute 16*Q - digits := x.signedRadix16() - - // Unwrap first loop iteration to save computing 16*identity - multiple := &projCached{} - tmp1 := &projP1xP1{} - tmp2 := &projP2{} - table.SelectInto(multiple, digits[63]) - - v.Set(NewIdentityPoint()) - tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords - for i := 62; i >= 0; i-- { - tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords - tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords - tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords - v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords - table.SelectInto(multiple, digits[i]) - tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords - } - v.fromP1xP1(tmp1) - return v -} - -// basepointNafTable is the nafLookupTable8 for the basepoint. -// It is precomputed the first time it's used. -func basepointNafTable() *nafLookupTable8 { - basepointNafTablePrecomp.initOnce.Do(func() { - basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint()) - }) - return &basepointNafTablePrecomp.table -} - -var basepointNafTablePrecomp struct { - table nafLookupTable8 - initOnce sync.Once -} - -// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical -// generator, and returns v. -// -// Execution time depends on the inputs. -func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point { - checkInitialized(A) - - // Similarly to the single variable-base approach, we compute - // digits and use them with a lookup table. However, because - // we are allowed to do variable-time operations, we don't - // need constant-time lookups or constant-time digit - // computations. - // - // So we use a non-adjacent form of some width w instead of - // radix 16. This is like a binary representation (one digit - // for each binary place) but we allow the digits to grow in - // magnitude up to 2^{w-1} so that the nonzero digits are as - // sparse as possible. Intuitively, this "condenses" the - // "mass" of the scalar onto sparse coefficients (meaning - // fewer additions). - - basepointNafTable := basepointNafTable() - var aTable nafLookupTable5 - aTable.FromP3(A) - // Because the basepoint is fixed, we can use a wider NAF - // corresponding to a bigger table. - aNaf := a.nonAdjacentForm(5) - bNaf := b.nonAdjacentForm(8) - - // Find the first nonzero coefficient. - i := 255 - for j := i; j >= 0; j-- { - if aNaf[j] != 0 || bNaf[j] != 0 { - break - } - } - - multA := &projCached{} - multB := &affineCached{} - tmp1 := &projP1xP1{} - tmp2 := &projP2{} - tmp2.Zero() - - // Move from high to low bits, doubling the accumulator - // at each iteration and checking whether there is a nonzero - // coefficient to look up a multiple of. - for ; i >= 0; i-- { - tmp1.Double(tmp2) - - // Only update v if we have a nonzero coeff to add in. - if aNaf[i] > 0 { - v.fromP1xP1(tmp1) - aTable.SelectInto(multA, aNaf[i]) - tmp1.Add(v, multA) - } else if aNaf[i] < 0 { - v.fromP1xP1(tmp1) - aTable.SelectInto(multA, -aNaf[i]) - tmp1.Sub(v, multA) - } - - if bNaf[i] > 0 { - v.fromP1xP1(tmp1) - basepointNafTable.SelectInto(multB, bNaf[i]) - tmp1.AddAffine(v, multB) - } else if bNaf[i] < 0 { - v.fromP1xP1(tmp1) - basepointNafTable.SelectInto(multB, -bNaf[i]) - tmp1.SubAffine(v, multB) - } - - tmp2.FromP1xP1(tmp1) - } - - v.fromP2(tmp2) - return v -} diff --git a/vendor/filippo.io/edwards25519/tables.go b/vendor/filippo.io/edwards25519/tables.go deleted file mode 100644 index 83234bb..0000000 --- a/vendor/filippo.io/edwards25519/tables.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package edwards25519 - -import ( - "crypto/subtle" -) - -// A dynamic lookup table for variable-base, constant-time scalar muls. -type projLookupTable struct { - points [8]projCached -} - -// A precomputed lookup table for fixed-base, constant-time scalar muls. -type affineLookupTable struct { - points [8]affineCached -} - -// A dynamic lookup table for variable-base, variable-time scalar muls. -type nafLookupTable5 struct { - points [8]projCached -} - -// A precomputed lookup table for fixed-base, variable-time scalar muls. -type nafLookupTable8 struct { - points [64]affineCached -} - -// Constructors. - -// Builds a lookup table at runtime. Fast. -func (v *projLookupTable) FromP3(q *Point) { - // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q - // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q - v.points[0].FromP3(q) - tmpP3 := Point{} - tmpP1xP1 := projP1xP1{} - for i := 0; i < 7; i++ { - // Compute (i+1)*Q as Q + i*Q and convert to a projCached - // This is needlessly complicated because the API has explicit - // receivers instead of creating stack objects and relying on RVO - v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i]))) - } -} - -// This is not optimised for speed; fixed-base tables should be precomputed. -func (v *affineLookupTable) FromP3(q *Point) { - // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q - // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q - v.points[0].FromP3(q) - tmpP3 := Point{} - tmpP1xP1 := projP1xP1{} - for i := 0; i < 7; i++ { - // Compute (i+1)*Q as Q + i*Q and convert to affineCached - v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i]))) - } -} - -// Builds a lookup table at runtime. Fast. -func (v *nafLookupTable5) FromP3(q *Point) { - // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q - // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q - v.points[0].FromP3(q) - q2 := Point{} - q2.Add(q, q) - tmpP3 := Point{} - tmpP1xP1 := projP1xP1{} - for i := 0; i < 7; i++ { - v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i]))) - } -} - -// This is not optimised for speed; fixed-base tables should be precomputed. -func (v *nafLookupTable8) FromP3(q *Point) { - v.points[0].FromP3(q) - q2 := Point{} - q2.Add(q, q) - tmpP3 := Point{} - tmpP1xP1 := projP1xP1{} - for i := 0; i < 63; i++ { - v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i]))) - } -} - -// Selectors. - -// Set dest to x*Q, where -8 <= x <= 8, in constant time. -func (v *projLookupTable) SelectInto(dest *projCached, x int8) { - // Compute xabs = |x| - xmask := x >> 7 - xabs := uint8((x + xmask) ^ xmask) - - dest.Zero() - for j := 1; j <= 8; j++ { - // Set dest = j*Q if |x| = j - cond := subtle.ConstantTimeByteEq(xabs, uint8(j)) - dest.Select(&v.points[j-1], dest, cond) - } - // Now dest = |x|*Q, conditionally negate to get x*Q - dest.CondNeg(int(xmask & 1)) -} - -// Set dest to x*Q, where -8 <= x <= 8, in constant time. -func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) { - // Compute xabs = |x| - xmask := x >> 7 - xabs := uint8((x + xmask) ^ xmask) - - dest.Zero() - for j := 1; j <= 8; j++ { - // Set dest = j*Q if |x| = j - cond := subtle.ConstantTimeByteEq(xabs, uint8(j)) - dest.Select(&v.points[j-1], dest, cond) - } - // Now dest = |x|*Q, conditionally negate to get x*Q - dest.CondNeg(int(xmask & 1)) -} - -// Given odd x with 0 < x < 2^4, return x*Q (in variable time). -func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) { - *dest = v.points[x/2] -} - -// Given odd x with 0 < x < 2^7, return x*Q (in variable time). -func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) { - *dest = v.points[x/2] -} diff --git a/vendor/github.com/Masterminds/semver/.travis.yml b/vendor/github.com/Masterminds/semver/.travis.yml deleted file mode 100644 index 3d9ebad..0000000 --- a/vendor/github.com/Masterminds/semver/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go - -go: - - 1.6.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x - - tip - -# Setting sudo access to false will let Travis CI use containers rather than -# VMs to run the tests. For more details see: -# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/ -# - http://docs.travis-ci.com/user/workers/standard-infrastructure/ -sudo: false - -script: - - make setup - - make test - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/06e3328629952dabe3e0 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always diff --git a/vendor/github.com/Masterminds/semver/CHANGELOG.md b/vendor/github.com/Masterminds/semver/CHANGELOG.md deleted file mode 100644 index b888e20..0000000 --- a/vendor/github.com/Masterminds/semver/CHANGELOG.md +++ /dev/null @@ -1,86 +0,0 @@ -# 1.4.2 (2018-04-10) - -## Changed -- #72: Updated the docs to point to vert for a console appliaction -- #71: Update the docs on pre-release comparator handling - -## Fixed -- #70: Fix the handling of pre-releases and the 0.0.0 release edge case - -# 1.4.1 (2018-04-02) - -## Fixed -- Fixed #64: Fix pre-release precedence issue (thanks @uudashr) - -# 1.4.0 (2017-10-04) - -## Changed -- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill) - -# 1.3.1 (2017-07-10) - -## Fixed -- Fixed #57: number comparisons in prerelease sometimes inaccurate - -# 1.3.0 (2017-05-02) - -## Added -- #45: Added json (un)marshaling support (thanks @mh-cbon) -- Stability marker. See https://masterminds.github.io/stability/ - -## Fixed -- #51: Fix handling of single digit tilde constraint (thanks @dgodd) - -## Changed -- #55: The godoc icon moved from png to svg - -# 1.2.3 (2017-04-03) - -## Fixed -- #46: Fixed 0.x.x and 0.0.x in constraints being treated as * - -# Release 1.2.2 (2016-12-13) - -## Fixed -- #34: Fixed issue where hyphen range was not working with pre-release parsing. - -# Release 1.2.1 (2016-11-28) - -## Fixed -- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha" - properly. - -# Release 1.2.0 (2016-11-04) - -## Added -- #20: Added MustParse function for versions (thanks @adamreese) -- #15: Added increment methods on versions (thanks @mh-cbon) - -## Fixed -- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and - might not satisfy the intended compatibility. The change here ignores pre-releases - on constraint checks (e.g., ~ or ^) when a pre-release is not part of the - constraint. For example, `^1.2.3` will ignore pre-releases while - `^1.2.3-alpha` will include them. - -# Release 1.1.1 (2016-06-30) - -## Changed -- Issue #9: Speed up version comparison performance (thanks @sdboyer) -- Issue #8: Added benchmarks (thanks @sdboyer) -- Updated Go Report Card URL to new location -- Updated Readme to add code snippet formatting (thanks @mh-cbon) -- Updating tagging to v[SemVer] structure for compatibility with other tools. - -# Release 1.1.0 (2016-03-11) - -- Issue #2: Implemented validation to provide reasons a versions failed a - constraint. - -# Release 1.0.1 (2015-12-31) - -- Fixed #1: * constraint failing on valid versions. - -# Release 1.0.0 (2015-10-20) - -- Initial release diff --git a/vendor/github.com/Masterminds/semver/LICENSE.txt b/vendor/github.com/Masterminds/semver/LICENSE.txt deleted file mode 100644 index 0da4aea..0000000 --- a/vendor/github.com/Masterminds/semver/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -The Masterminds -Copyright (C) 2014-2015, Matt Butcher and Matt Farina - -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. diff --git a/vendor/github.com/Masterminds/semver/Makefile b/vendor/github.com/Masterminds/semver/Makefile deleted file mode 100644 index a7a1b4e..0000000 --- a/vendor/github.com/Masterminds/semver/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -.PHONY: setup -setup: - go get -u gopkg.in/alecthomas/gometalinter.v1 - gometalinter.v1 --install - -.PHONY: test -test: validate lint - @echo "==> Running tests" - go test -v - -.PHONY: validate -validate: - @echo "==> Running static validations" - @gometalinter.v1 \ - --disable-all \ - --enable deadcode \ - --severity deadcode:error \ - --enable gofmt \ - --enable gosimple \ - --enable ineffassign \ - --enable misspell \ - --enable vet \ - --tests \ - --vendor \ - --deadline 60s \ - ./... || exit_code=1 - -.PHONY: lint -lint: - @echo "==> Running linters" - @gometalinter.v1 \ - --disable-all \ - --enable golint \ - --vendor \ - --deadline 60s \ - ./... || : diff --git a/vendor/github.com/Masterminds/semver/README.md b/vendor/github.com/Masterminds/semver/README.md deleted file mode 100644 index af845f1..0000000 --- a/vendor/github.com/Masterminds/semver/README.md +++ /dev/null @@ -1,186 +0,0 @@ -# SemVer - -The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to: - -* Parse semantic versions -* Sort semantic versions -* Check if a semantic version fits within a set of constraints -* Optionally work with a `v` prefix - -[![Stability: -Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html) -[![Build Status](https://travis-ci.org/Masterminds/semver.svg)](https://travis-ci.org/Masterminds/semver) [![Build status](https://ci.appveyor.com/api/projects/status/jfk66lib7hb985k8/branch/master?svg=true&passingText=windows%20build%20passing&failingText=windows%20build%20failing)](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [![GoDoc](https://godoc.org/github.com/Masterminds/semver?status.svg)](https://godoc.org/github.com/Masterminds/semver) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver) - -If you are looking for a command line tool for version comparisons please see -[vert](https://github.com/Masterminds/vert) which uses this library. - -## Parsing Semantic Versions - -To parse a semantic version use the `NewVersion` function. For example, - -```go - v, err := semver.NewVersion("1.2.3-beta.1+build345") -``` - -If there is an error the version wasn't parseable. The version object has methods -to get the parts of the version, compare it to other versions, convert the -version back into a string, and get the original string. For more details -please see the [documentation](https://godoc.org/github.com/Masterminds/semver). - -## Sorting Semantic Versions - -A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/) -package from the standard library. For example, - -```go - raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",} - vs := make([]*semver.Version, len(raw)) - for i, r := range raw { - v, err := semver.NewVersion(r) - if err != nil { - t.Errorf("Error parsing version: %s", err) - } - - vs[i] = v - } - - sort.Sort(semver.Collection(vs)) -``` - -## Checking Version Constraints - -Checking a version against version constraints is one of the most featureful -parts of the package. - -```go - c, err := semver.NewConstraint(">= 1.2.3") - if err != nil { - // Handle constraint not being parseable. - } - - v, _ := semver.NewVersion("1.3") - if err != nil { - // Handle version not being parseable. - } - // Check if the version meets the constraints. The a variable will be true. - a := c.Check(v) -``` - -## Basic Comparisons - -There are two elements to the comparisons. First, a comparison string is a list -of comma separated and comparisons. These are then separated by || separated or -comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a -comparison that's greater than or equal to 1.2 and less than 3.0.0 or is -greater than or equal to 4.2.3. - -The basic comparisons are: - -* `=`: equal (aliased to no operator) -* `!=`: not equal -* `>`: greater than -* `<`: less than -* `>=`: greater than or equal to -* `<=`: less than or equal to - -## Working With Pre-release Versions - -Pre-releases, for those not familiar with them, are used for software releases -prior to stable or generally available releases. Examples of pre-releases include -development, alpha, beta, and release candidate releases. A pre-release may be -a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the -order of precidence, pre-releases come before their associated releases. In this -example `1.2.3-beta.1 < 1.2.3`. - -According to the Semantic Version specification pre-releases may not be -API compliant with their release counterpart. It says, - -> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. - -SemVer comparisons without a pre-release comparator will skip pre-release versions. -For example, `>=1.2.3` will skip pre-releases when looking at a list of releases -while `>=1.2.3-0` will evaluate and find pre-releases. - -The reason for the `0` as a pre-release version in the example comparison is -because pre-releases can only contain ASCII alphanumerics and hyphens (along with -`.` separators), per the spec. Sorting happens in ASCII sort order, again per the spec. The lowest character is a `0` in ASCII sort order (see an [ASCII Table](http://www.asciitable.com/)) - -Understanding ASCII sort ordering is important because A-Z comes before a-z. That -means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case -sensitivity doesn't apply here. This is due to ASCII sort ordering which is what -the spec specifies. - -## Hyphen Range Comparisons - -There are multiple methods to handle ranges and the first is hyphens ranges. -These look like: - -* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5` -* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5` - -## Wildcards In Comparisons - -The `x`, `X`, and `*` characters can be used as a wildcard character. This works -for all comparison operators. When used on the `=` operator it falls -back to the pack level comparison (see tilde below). For example, - -* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` -* `>= 1.2.x` is equivalent to `>= 1.2.0` -* `<= 2.x` is equivalent to `< 3` -* `*` is equivalent to `>= 0.0.0` - -## Tilde Range Comparisons (Patch) - -The tilde (`~`) comparison operator is for patch level ranges when a minor -version is specified and major level changes when the minor number is missing. -For example, - -* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0` -* `~1` is equivalent to `>= 1, < 2` -* `~2.3` is equivalent to `>= 2.3, < 2.4` -* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` -* `~1.x` is equivalent to `>= 1, < 2` - -## Caret Range Comparisons (Major) - -The caret (`^`) comparison operator is for major level changes. This is useful -when comparisons of API versions as a major change is API breaking. For example, - -* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0` -* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0` -* `^2.3` is equivalent to `>= 2.3, < 3` -* `^2.x` is equivalent to `>= 2.0.0, < 3` - -# Validation - -In addition to testing a version against a constraint, a version can be validated -against a constraint. When validation fails a slice of errors containing why a -version didn't meet the constraint is returned. For example, - -```go - c, err := semver.NewConstraint("<= 1.2.3, >= 1.4") - if err != nil { - // Handle constraint not being parseable. - } - - v, _ := semver.NewVersion("1.3") - if err != nil { - // Handle version not being parseable. - } - - // Validate a version against a constraint. - a, msgs := c.Validate(v) - // a is false - for _, m := range msgs { - fmt.Println(m) - - // Loops over the errors which would read - // "1.3 is greater than 1.2.3" - // "1.3 is less than 1.4" - } -``` - -# Contribute - -If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues) -or [create a pull request](https://github.com/Masterminds/semver/pulls). diff --git a/vendor/github.com/Masterminds/semver/appveyor.yml b/vendor/github.com/Masterminds/semver/appveyor.yml deleted file mode 100644 index b2778df..0000000 --- a/vendor/github.com/Masterminds/semver/appveyor.yml +++ /dev/null @@ -1,44 +0,0 @@ -version: build-{build}.{branch} - -clone_folder: C:\gopath\src\github.com\Masterminds\semver -shallow_clone: true - -environment: - GOPATH: C:\gopath - -platform: - - x64 - -install: - - go version - - go env - - go get -u gopkg.in/alecthomas/gometalinter.v1 - - set PATH=%PATH%;%GOPATH%\bin - - gometalinter.v1.exe --install - -build_script: - - go install -v ./... - -test_script: - - "gometalinter.v1 \ - --disable-all \ - --enable deadcode \ - --severity deadcode:error \ - --enable gofmt \ - --enable gosimple \ - --enable ineffassign \ - --enable misspell \ - --enable vet \ - --tests \ - --vendor \ - --deadline 60s \ - ./... || exit_code=1" - - "gometalinter.v1 \ - --disable-all \ - --enable golint \ - --vendor \ - --deadline 60s \ - ./... || :" - - go test -v - -deploy: off diff --git a/vendor/github.com/Masterminds/semver/collection.go b/vendor/github.com/Masterminds/semver/collection.go deleted file mode 100644 index a782358..0000000 --- a/vendor/github.com/Masterminds/semver/collection.go +++ /dev/null @@ -1,24 +0,0 @@ -package semver - -// Collection is a collection of Version instances and implements the sort -// interface. See the sort package for more details. -// https://golang.org/pkg/sort/ -type Collection []*Version - -// Len returns the length of a collection. The number of Version instances -// on the slice. -func (c Collection) Len() int { - return len(c) -} - -// Less is needed for the sort interface to compare two Version objects on the -// slice. If checks if one is less than the other. -func (c Collection) Less(i, j int) bool { - return c[i].LessThan(c[j]) -} - -// Swap is needed for the sort interface to replace the Version objects -// at two different positions in the slice. -func (c Collection) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} diff --git a/vendor/github.com/Masterminds/semver/constraints.go b/vendor/github.com/Masterminds/semver/constraints.go deleted file mode 100644 index 2f3d779..0000000 --- a/vendor/github.com/Masterminds/semver/constraints.go +++ /dev/null @@ -1,406 +0,0 @@ -package semver - -import ( - "errors" - "fmt" - "regexp" - "strings" -) - -// Constraints is one or more constraint that a semantic version can be -// checked against. -type Constraints struct { - constraints [][]*constraint -} - -// NewConstraint returns a Constraints instance that a Version instance can -// be checked against. If there is a parse error it will be returned. -func NewConstraint(c string) (*Constraints, error) { - - // Rewrite - ranges into a comparison operation. - c = rewriteRange(c) - - ors := strings.Split(c, "||") - or := make([][]*constraint, len(ors)) - for k, v := range ors { - cs := strings.Split(v, ",") - result := make([]*constraint, len(cs)) - for i, s := range cs { - pc, err := parseConstraint(s) - if err != nil { - return nil, err - } - - result[i] = pc - } - or[k] = result - } - - o := &Constraints{constraints: or} - return o, nil -} - -// Check tests if a version satisfies the constraints. -func (cs Constraints) Check(v *Version) bool { - // loop over the ORs and check the inner ANDs - for _, o := range cs.constraints { - joy := true - for _, c := range o { - if !c.check(v) { - joy = false - break - } - } - - if joy { - return true - } - } - - return false -} - -// Validate checks if a version satisfies a constraint. If not a slice of -// reasons for the failure are returned in addition to a bool. -func (cs Constraints) Validate(v *Version) (bool, []error) { - // loop over the ORs and check the inner ANDs - var e []error - for _, o := range cs.constraints { - joy := true - for _, c := range o { - if !c.check(v) { - em := fmt.Errorf(c.msg, v, c.orig) - e = append(e, em) - joy = false - } - } - - if joy { - return true, []error{} - } - } - - return false, e -} - -var constraintOps map[string]cfunc -var constraintMsg map[string]string -var constraintRegex *regexp.Regexp - -func init() { - constraintOps = map[string]cfunc{ - "": constraintTildeOrEqual, - "=": constraintTildeOrEqual, - "!=": constraintNotEqual, - ">": constraintGreaterThan, - "<": constraintLessThan, - ">=": constraintGreaterThanEqual, - "=>": constraintGreaterThanEqual, - "<=": constraintLessThanEqual, - "=<": constraintLessThanEqual, - "~": constraintTilde, - "~>": constraintTilde, - "^": constraintCaret, - } - - constraintMsg = map[string]string{ - "": "%s is not equal to %s", - "=": "%s is not equal to %s", - "!=": "%s is equal to %s", - ">": "%s is less than or equal to %s", - "<": "%s is greater than or equal to %s", - ">=": "%s is less than %s", - "=>": "%s is less than %s", - "<=": "%s is greater than %s", - "=<": "%s is greater than %s", - "~": "%s does not have same major and minor version as %s", - "~>": "%s does not have same major and minor version as %s", - "^": "%s does not have same major version as %s", - } - - ops := make([]string, 0, len(constraintOps)) - for k := range constraintOps { - ops = append(ops, regexp.QuoteMeta(k)) - } - - constraintRegex = regexp.MustCompile(fmt.Sprintf( - `^\s*(%s)\s*(%s)\s*$`, - strings.Join(ops, "|"), - cvRegex)) - - constraintRangeRegex = regexp.MustCompile(fmt.Sprintf( - `\s*(%s)\s+-\s+(%s)\s*`, - cvRegex, cvRegex)) -} - -// An individual constraint -type constraint struct { - // The callback function for the restraint. It performs the logic for - // the constraint. - function cfunc - - msg string - - // The version used in the constraint check. For example, if a constraint - // is '<= 2.0.0' the con a version instance representing 2.0.0. - con *Version - - // The original parsed version (e.g., 4.x from != 4.x) - orig string - - // When an x is used as part of the version (e.g., 1.x) - minorDirty bool - dirty bool - patchDirty bool -} - -// Check if a version meets the constraint -func (c *constraint) check(v *Version) bool { - return c.function(v, c) -} - -type cfunc func(v *Version, c *constraint) bool - -func parseConstraint(c string) (*constraint, error) { - m := constraintRegex.FindStringSubmatch(c) - if m == nil { - return nil, fmt.Errorf("improper constraint: %s", c) - } - - ver := m[2] - orig := ver - minorDirty := false - patchDirty := false - dirty := false - if isX(m[3]) { - ver = "0.0.0" - dirty = true - } else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" { - minorDirty = true - dirty = true - ver = fmt.Sprintf("%s.0.0%s", m[3], m[6]) - } else if isX(strings.TrimPrefix(m[5], ".")) { - dirty = true - patchDirty = true - ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6]) - } - - con, err := NewVersion(ver) - if err != nil { - - // The constraintRegex should catch any regex parsing errors. So, - // we should never get here. - return nil, errors.New("constraint Parser Error") - } - - cs := &constraint{ - function: constraintOps[m[1]], - msg: constraintMsg[m[1]], - con: con, - orig: orig, - minorDirty: minorDirty, - patchDirty: patchDirty, - dirty: dirty, - } - return cs, nil -} - -// Constraint functions -func constraintNotEqual(v *Version, c *constraint) bool { - if c.dirty { - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if c.con.Major() != v.Major() { - return true - } - if c.con.Minor() != v.Minor() && !c.minorDirty { - return true - } else if c.minorDirty { - return false - } - - return false - } - - return !v.Equal(c.con) -} - -func constraintGreaterThan(v *Version, c *constraint) bool { - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - return v.Compare(c.con) == 1 -} - -func constraintLessThan(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if !c.dirty { - return v.Compare(c.con) < 0 - } - - if v.Major() > c.con.Major() { - return false - } else if v.Minor() > c.con.Minor() && !c.minorDirty { - return false - } - - return true -} - -func constraintGreaterThanEqual(v *Version, c *constraint) bool { - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - return v.Compare(c.con) >= 0 -} - -func constraintLessThanEqual(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if !c.dirty { - return v.Compare(c.con) <= 0 - } - - if v.Major() > c.con.Major() { - return false - } else if v.Minor() > c.con.Minor() && !c.minorDirty { - return false - } - - return true -} - -// ~*, ~>* --> >= 0.0.0 (any) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0 -func constraintTilde(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if v.LessThan(c.con) { - return false - } - - // ~0.0.0 is a special case where all constraints are accepted. It's - // equivalent to >= 0.0.0. - if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 && - !c.minorDirty && !c.patchDirty { - return true - } - - if v.Major() != c.con.Major() { - return false - } - - if v.Minor() != c.con.Minor() && !c.minorDirty { - return false - } - - return true -} - -// When there is a .x (dirty) status it automatically opts in to ~. Otherwise -// it's a straight = -func constraintTildeOrEqual(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if c.dirty { - c.msg = constraintMsg["~"] - return constraintTilde(v, c) - } - - return v.Equal(c.con) -} - -// ^* --> (any) -// ^2, ^2.x, ^2.x.x --> >=2.0.0, <3.0.0 -// ^2.0, ^2.0.x --> >=2.0.0, <3.0.0 -// ^1.2, ^1.2.x --> >=1.2.0, <2.0.0 -// ^1.2.3 --> >=1.2.3, <2.0.0 -// ^1.2.0 --> >=1.2.0, <2.0.0 -func constraintCaret(v *Version, c *constraint) bool { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false - } - - if v.LessThan(c.con) { - return false - } - - if v.Major() != c.con.Major() { - return false - } - - return true -} - -var constraintRangeRegex *regexp.Regexp - -const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` + - `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + - `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` - -func isX(x string) bool { - switch x { - case "x", "*", "X": - return true - default: - return false - } -} - -func rewriteRange(i string) string { - m := constraintRangeRegex.FindAllStringSubmatch(i, -1) - if m == nil { - return i - } - o := i - for _, v := range m { - t := fmt.Sprintf(">= %s, <= %s", v[1], v[11]) - o = strings.Replace(o, v[0], t, 1) - } - - return o -} diff --git a/vendor/github.com/Masterminds/semver/doc.go b/vendor/github.com/Masterminds/semver/doc.go deleted file mode 100644 index 6a6c24c..0000000 --- a/vendor/github.com/Masterminds/semver/doc.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go. - -Specifically it provides the ability to: - - * Parse semantic versions - * Sort semantic versions - * Check if a semantic version fits within a set of constraints - * Optionally work with a `v` prefix - -Parsing Semantic Versions - -To parse a semantic version use the `NewVersion` function. For example, - - v, err := semver.NewVersion("1.2.3-beta.1+build345") - -If there is an error the version wasn't parseable. The version object has methods -to get the parts of the version, compare it to other versions, convert the -version back into a string, and get the original string. For more details -please see the documentation at https://godoc.org/github.com/Masterminds/semver. - -Sorting Semantic Versions - -A set of versions can be sorted using the `sort` package from the standard library. -For example, - - raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",} - vs := make([]*semver.Version, len(raw)) - for i, r := range raw { - v, err := semver.NewVersion(r) - if err != nil { - t.Errorf("Error parsing version: %s", err) - } - - vs[i] = v - } - - sort.Sort(semver.Collection(vs)) - -Checking Version Constraints - -Checking a version against version constraints is one of the most featureful -parts of the package. - - c, err := semver.NewConstraint(">= 1.2.3") - if err != nil { - // Handle constraint not being parseable. - } - - v, err := semver.NewVersion("1.3") - if err != nil { - // Handle version not being parseable. - } - // Check if the version meets the constraints. The a variable will be true. - a := c.Check(v) - -Basic Comparisons - -There are two elements to the comparisons. First, a comparison string is a list -of comma separated and comparisons. These are then separated by || separated or -comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a -comparison that's greater than or equal to 1.2 and less than 3.0.0 or is -greater than or equal to 4.2.3. - -The basic comparisons are: - - * `=`: equal (aliased to no operator) - * `!=`: not equal - * `>`: greater than - * `<`: less than - * `>=`: greater than or equal to - * `<=`: less than or equal to - -Hyphen Range Comparisons - -There are multiple methods to handle ranges and the first is hyphens ranges. -These look like: - - * `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5` - * `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5` - -Wildcards In Comparisons - -The `x`, `X`, and `*` characters can be used as a wildcard character. This works -for all comparison operators. When used on the `=` operator it falls -back to the pack level comparison (see tilde below). For example, - - * `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` - * `>= 1.2.x` is equivalent to `>= 1.2.0` - * `<= 2.x` is equivalent to `<= 3` - * `*` is equivalent to `>= 0.0.0` - -Tilde Range Comparisons (Patch) - -The tilde (`~`) comparison operator is for patch level ranges when a minor -version is specified and major level changes when the minor number is missing. -For example, - - * `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0` - * `~1` is equivalent to `>= 1, < 2` - * `~2.3` is equivalent to `>= 2.3, < 2.4` - * `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` - * `~1.x` is equivalent to `>= 1, < 2` - -Caret Range Comparisons (Major) - -The caret (`^`) comparison operator is for major level changes. This is useful -when comparisons of API versions as a major change is API breaking. For example, - - * `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0` - * `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0` - * `^2.3` is equivalent to `>= 2.3, < 3` - * `^2.x` is equivalent to `>= 2.0.0, < 3` -*/ -package semver diff --git a/vendor/github.com/Masterminds/semver/version.go b/vendor/github.com/Masterminds/semver/version.go deleted file mode 100644 index ab3a368..0000000 --- a/vendor/github.com/Masterminds/semver/version.go +++ /dev/null @@ -1,421 +0,0 @@ -package semver - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "regexp" - "strconv" - "strings" -) - -// The compiled version of the regex created at init() is cached here so it -// only needs to be created once. -var versionRegex *regexp.Regexp -var validPrereleaseRegex *regexp.Regexp - -var ( - // ErrInvalidSemVer is returned a version is found to be invalid when - // being parsed. - ErrInvalidSemVer = errors.New("Invalid Semantic Version") - - // ErrInvalidMetadata is returned when the metadata is an invalid format - ErrInvalidMetadata = errors.New("Invalid Metadata string") - - // ErrInvalidPrerelease is returned when the pre-release is an invalid format - ErrInvalidPrerelease = errors.New("Invalid Prerelease string") -) - -// SemVerRegex is the regular expression used to parse a semantic version. -const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + - `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + - `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` - -// ValidPrerelease is the regular expression which validates -// both prerelease and metadata values. -const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)` - -// Version represents a single semantic version. -type Version struct { - major, minor, patch int64 - pre string - metadata string - original string -} - -func init() { - versionRegex = regexp.MustCompile("^" + SemVerRegex + "$") - validPrereleaseRegex = regexp.MustCompile(ValidPrerelease) -} - -// NewVersion parses a given version and returns an instance of Version or -// an error if unable to parse the version. -func NewVersion(v string) (*Version, error) { - m := versionRegex.FindStringSubmatch(v) - if m == nil { - return nil, ErrInvalidSemVer - } - - sv := &Version{ - metadata: m[8], - pre: m[5], - original: v, - } - - var temp int64 - temp, err := strconv.ParseInt(m[1], 10, 64) - if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) - } - sv.major = temp - - if m[2] != "" { - temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 64) - if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) - } - sv.minor = temp - } else { - sv.minor = 0 - } - - if m[3] != "" { - temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 64) - if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) - } - sv.patch = temp - } else { - sv.patch = 0 - } - - return sv, nil -} - -// MustParse parses a given version and panics on error. -func MustParse(v string) *Version { - sv, err := NewVersion(v) - if err != nil { - panic(err) - } - return sv -} - -// String converts a Version object to a string. -// Note, if the original version contained a leading v this version will not. -// See the Original() method to retrieve the original value. Semantic Versions -// don't contain a leading v per the spec. Instead it's optional on -// implementation. -func (v *Version) String() string { - var buf bytes.Buffer - - fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch) - if v.pre != "" { - fmt.Fprintf(&buf, "-%s", v.pre) - } - if v.metadata != "" { - fmt.Fprintf(&buf, "+%s", v.metadata) - } - - return buf.String() -} - -// Original returns the original value passed in to be parsed. -func (v *Version) Original() string { - return v.original -} - -// Major returns the major version. -func (v *Version) Major() int64 { - return v.major -} - -// Minor returns the minor version. -func (v *Version) Minor() int64 { - return v.minor -} - -// Patch returns the patch version. -func (v *Version) Patch() int64 { - return v.patch -} - -// Prerelease returns the pre-release version. -func (v *Version) Prerelease() string { - return v.pre -} - -// Metadata returns the metadata on the version. -func (v *Version) Metadata() string { - return v.metadata -} - -// originalVPrefix returns the original 'v' prefix if any. -func (v *Version) originalVPrefix() string { - - // Note, only lowercase v is supported as a prefix by the parser. - if v.original != "" && v.original[:1] == "v" { - return v.original[:1] - } - return "" -} - -// IncPatch produces the next patch version. -// If the current version does not have prerelease/metadata information, -// it unsets metadata and prerelease values, increments patch number. -// If the current version has any of prerelease or metadata information, -// it unsets both values and keeps curent patch value -func (v Version) IncPatch() Version { - vNext := v - // according to http://semver.org/#spec-item-9 - // Pre-release versions have a lower precedence than the associated normal version. - // according to http://semver.org/#spec-item-10 - // Build metadata SHOULD be ignored when determining version precedence. - if v.pre != "" { - vNext.metadata = "" - vNext.pre = "" - } else { - vNext.metadata = "" - vNext.pre = "" - vNext.patch = v.patch + 1 - } - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext -} - -// IncMinor produces the next minor version. -// Sets patch to 0. -// Increments minor number. -// Unsets metadata. -// Unsets prerelease status. -func (v Version) IncMinor() Version { - vNext := v - vNext.metadata = "" - vNext.pre = "" - vNext.patch = 0 - vNext.minor = v.minor + 1 - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext -} - -// IncMajor produces the next major version. -// Sets patch to 0. -// Sets minor to 0. -// Increments major number. -// Unsets metadata. -// Unsets prerelease status. -func (v Version) IncMajor() Version { - vNext := v - vNext.metadata = "" - vNext.pre = "" - vNext.patch = 0 - vNext.minor = 0 - vNext.major = v.major + 1 - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext -} - -// SetPrerelease defines the prerelease value. -// Value must not include the required 'hypen' prefix. -func (v Version) SetPrerelease(prerelease string) (Version, error) { - vNext := v - if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) { - return vNext, ErrInvalidPrerelease - } - vNext.pre = prerelease - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext, nil -} - -// SetMetadata defines metadata value. -// Value must not include the required 'plus' prefix. -func (v Version) SetMetadata(metadata string) (Version, error) { - vNext := v - if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) { - return vNext, ErrInvalidMetadata - } - vNext.metadata = metadata - vNext.original = v.originalVPrefix() + "" + vNext.String() - return vNext, nil -} - -// LessThan tests if one version is less than another one. -func (v *Version) LessThan(o *Version) bool { - return v.Compare(o) < 0 -} - -// GreaterThan tests if one version is greater than another one. -func (v *Version) GreaterThan(o *Version) bool { - return v.Compare(o) > 0 -} - -// Equal tests if two versions are equal to each other. -// Note, versions can be equal with different metadata since metadata -// is not considered part of the comparable version. -func (v *Version) Equal(o *Version) bool { - return v.Compare(o) == 0 -} - -// Compare compares this version to another one. It returns -1, 0, or 1 if -// the version smaller, equal, or larger than the other version. -// -// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is -// lower than the version without a prerelease. -func (v *Version) Compare(o *Version) int { - // Compare the major, minor, and patch version for differences. If a - // difference is found return the comparison. - if d := compareSegment(v.Major(), o.Major()); d != 0 { - return d - } - if d := compareSegment(v.Minor(), o.Minor()); d != 0 { - return d - } - if d := compareSegment(v.Patch(), o.Patch()); d != 0 { - return d - } - - // At this point the major, minor, and patch versions are the same. - ps := v.pre - po := o.Prerelease() - - if ps == "" && po == "" { - return 0 - } - if ps == "" { - return 1 - } - if po == "" { - return -1 - } - - return comparePrerelease(ps, po) -} - -// UnmarshalJSON implements JSON.Unmarshaler interface. -func (v *Version) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - temp, err := NewVersion(s) - if err != nil { - return err - } - v.major = temp.major - v.minor = temp.minor - v.patch = temp.patch - v.pre = temp.pre - v.metadata = temp.metadata - v.original = temp.original - temp = nil - return nil -} - -// MarshalJSON implements JSON.Marshaler interface. -func (v *Version) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -func compareSegment(v, o int64) int { - if v < o { - return -1 - } - if v > o { - return 1 - } - - return 0 -} - -func comparePrerelease(v, o string) int { - - // split the prelease versions by their part. The separator, per the spec, - // is a . - sparts := strings.Split(v, ".") - oparts := strings.Split(o, ".") - - // Find the longer length of the parts to know how many loop iterations to - // go through. - slen := len(sparts) - olen := len(oparts) - - l := slen - if olen > slen { - l = olen - } - - // Iterate over each part of the prereleases to compare the differences. - for i := 0; i < l; i++ { - // Since the lentgh of the parts can be different we need to create - // a placeholder. This is to avoid out of bounds issues. - stemp := "" - if i < slen { - stemp = sparts[i] - } - - otemp := "" - if i < olen { - otemp = oparts[i] - } - - d := comparePrePart(stemp, otemp) - if d != 0 { - return d - } - } - - // Reaching here means two versions are of equal value but have different - // metadata (the part following a +). They are not identical in string form - // but the version comparison finds them to be equal. - return 0 -} - -func comparePrePart(s, o string) int { - // Fastpath if they are equal - if s == o { - return 0 - } - - // When s or o are empty we can use the other in an attempt to determine - // the response. - if s == "" { - if o != "" { - return -1 - } - return 1 - } - - if o == "" { - if s != "" { - return 1 - } - return -1 - } - - // When comparing strings "99" is greater than "103". To handle - // cases like this we need to detect numbers and compare them. - - oi, n1 := strconv.ParseInt(o, 10, 64) - si, n2 := strconv.ParseInt(s, 10, 64) - - // The case where both are strings compare the strings - if n1 != nil && n2 != nil { - if s > o { - return 1 - } - return -1 - } else if n1 != nil { - // o is a string and s is a number - return -1 - } else if n2 != nil { - // s is a string and o is a number - return 1 - } - // Both are numbers - if si > oi { - return 1 - } - return -1 - -} diff --git a/vendor/github.com/ant0ine/go-json-rest/LICENSE b/vendor/github.com/ant0ine/go-json-rest/LICENSE deleted file mode 100644 index 7800c4b..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) 2013-2016 Antoine Imbert - -The MIT License - -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. diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/access_log_apache.go b/vendor/github.com/ant0ine/go-json-rest/rest/access_log_apache.go deleted file mode 100644 index d82894a..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/access_log_apache.go +++ /dev/null @@ -1,236 +0,0 @@ -package rest - -import ( - "bytes" - "fmt" - "log" - "net" - "os" - "strings" - "text/template" - "time" -) - -// TODO Future improvements: -// * support %{strftime}t ? -// * support %{
}o to print headers - -// AccessLogFormat defines the format of the access log record. -// This implementation is a subset of Apache mod_log_config. -// (See http://httpd.apache.org/docs/2.0/mod/mod_log_config.html) -// -// %b content length in bytes, - if 0 -// %B content length in bytes -// %D response elapsed time in microseconds -// %h remote address -// %H server protocol -// %l identd logname, not supported, - -// %m http method -// %P process id -// %q query string -// %r first line of the request -// %s status code -// %S status code preceeded by a terminal color -// %t time of the request -// %T response elapsed time in seconds, 3 decimals -// %u remote user, - if missing -// %{User-Agent}i user agent, - if missing -// %{Referer}i referer, - is missing -// -// Some predefined formats are provided as contants. -type AccessLogFormat string - -const ( - // CommonLogFormat is the Common Log Format (CLF). - CommonLogFormat = "%h %l %u %t \"%r\" %s %b" - - // CombinedLogFormat is the NCSA extended/combined log format. - CombinedLogFormat = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"" - - // DefaultLogFormat is the default format, colored output and response time, convenient for development. - DefaultLogFormat = "%t %S\033[0m \033[36;1m%Dμs\033[0m \"%r\" \033[1;30m%u \"%{User-Agent}i\"\033[0m" -) - -// AccessLogApacheMiddleware produces the access log following a format inspired by Apache -// mod_log_config. It depends on TimerMiddleware and RecorderMiddleware that should be in the wrapped -// middlewares. It also uses request.Env["REMOTE_USER"].(string) set by the auth middlewares. -type AccessLogApacheMiddleware struct { - - // Logger points to the logger object used by this middleware, it defaults to - // log.New(os.Stderr, "", 0). - Logger *log.Logger - - // Format defines the format of the access log record. See AccessLogFormat for the details. - // It defaults to DefaultLogFormat. - Format AccessLogFormat - - textTemplate *template.Template -} - -// MiddlewareFunc makes AccessLogApacheMiddleware implement the Middleware interface. -func (mw *AccessLogApacheMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - // set the default Logger - if mw.Logger == nil { - mw.Logger = log.New(os.Stderr, "", 0) - } - - // set default format - if mw.Format == "" { - mw.Format = DefaultLogFormat - } - - mw.convertFormat() - - return func(w ResponseWriter, r *Request) { - - // call the handler - h(w, r) - - util := &accessLogUtil{w, r} - - mw.Logger.Print(mw.executeTextTemplate(util)) - } -} - -var apacheAdapter = strings.NewReplacer( - "%b", "{{.BytesWritten | dashIf0}}", - "%B", "{{.BytesWritten}}", - "%D", "{{.ResponseTime | microseconds}}", - "%h", "{{.ApacheRemoteAddr}}", - "%H", "{{.R.Proto}}", - "%l", "-", - "%m", "{{.R.Method}}", - "%P", "{{.Pid}}", - "%q", "{{.ApacheQueryString}}", - "%r", "{{.R.Method}} {{.R.URL.RequestURI}} {{.R.Proto}}", - "%s", "{{.StatusCode}}", - "%S", "\033[{{.StatusCode | statusCodeColor}}m{{.StatusCode}}", - "%t", "{{if .StartTime}}{{.StartTime.Format \"02/Jan/2006:15:04:05 -0700\"}}{{end}}", - "%T", "{{if .ResponseTime}}{{.ResponseTime.Seconds | printf \"%.3f\"}}{{end}}", - "%u", "{{.RemoteUser | dashIfEmptyStr}}", - "%{User-Agent}i", "{{.R.UserAgent | dashIfEmptyStr}}", - "%{Referer}i", "{{.R.Referer | dashIfEmptyStr}}", -) - -// Convert the Apache access log format into a text/template -func (mw *AccessLogApacheMiddleware) convertFormat() { - - tmplText := apacheAdapter.Replace(string(mw.Format)) - - funcMap := template.FuncMap{ - "dashIfEmptyStr": func(value string) string { - if value == "" { - return "-" - } - return value - }, - "dashIf0": func(value int64) string { - if value == 0 { - return "-" - } - return fmt.Sprintf("%d", value) - }, - "microseconds": func(dur *time.Duration) string { - if dur != nil { - return fmt.Sprintf("%d", dur.Nanoseconds()/1000) - } - return "" - }, - "statusCodeColor": func(statusCode int) string { - if statusCode >= 400 && statusCode < 500 { - return "1;33" - } else if statusCode >= 500 { - return "0;31" - } - return "0;32" - }, - } - - var err error - mw.textTemplate, err = template.New("accessLog").Funcs(funcMap).Parse(tmplText) - if err != nil { - panic(err) - } -} - -// Execute the text template with the data derived from the request, and return a string. -func (mw *AccessLogApacheMiddleware) executeTextTemplate(util *accessLogUtil) string { - buf := bytes.NewBufferString("") - err := mw.textTemplate.Execute(buf, util) - if err != nil { - panic(err) - } - return buf.String() -} - -// accessLogUtil provides a collection of utility functions that devrive data from the Request object. -// This object is used to provide data to the Apache Style template and the the JSON log record. -type accessLogUtil struct { - W ResponseWriter - R *Request -} - -// As stored by the auth middlewares. -func (u *accessLogUtil) RemoteUser() string { - if u.R.Env["REMOTE_USER"] != nil { - return u.R.Env["REMOTE_USER"].(string) - } - return "" -} - -// If qs exists then return it with a leadin "?", apache log style. -func (u *accessLogUtil) ApacheQueryString() string { - if u.R.URL.RawQuery != "" { - return "?" + u.R.URL.RawQuery - } - return "" -} - -// When the request entered the timer middleware. -func (u *accessLogUtil) StartTime() *time.Time { - if u.R.Env["START_TIME"] != nil { - return u.R.Env["START_TIME"].(*time.Time) - } - return nil -} - -// If remoteAddr is set then return is without the port number, apache log style. -func (u *accessLogUtil) ApacheRemoteAddr() string { - remoteAddr := u.R.RemoteAddr - if remoteAddr != "" { - if ip, _, err := net.SplitHostPort(remoteAddr); err == nil { - return ip - } - } - return "" -} - -// As recorded by the recorder middleware. -func (u *accessLogUtil) StatusCode() int { - if u.R.Env["STATUS_CODE"] != nil { - return u.R.Env["STATUS_CODE"].(int) - } - return 0 -} - -// As mesured by the timer middleware. -func (u *accessLogUtil) ResponseTime() *time.Duration { - if u.R.Env["ELAPSED_TIME"] != nil { - return u.R.Env["ELAPSED_TIME"].(*time.Duration) - } - return nil -} - -// Process id. -func (u *accessLogUtil) Pid() int { - return os.Getpid() -} - -// As recorded by the recorder middleware. -func (u *accessLogUtil) BytesWritten() int64 { - if u.R.Env["BYTES_WRITTEN"] != nil { - return u.R.Env["BYTES_WRITTEN"].(int64) - } - return 0 -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/access_log_json.go b/vendor/github.com/ant0ine/go-json-rest/rest/access_log_json.go deleted file mode 100644 index a6bc175..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/access_log_json.go +++ /dev/null @@ -1,88 +0,0 @@ -package rest - -import ( - "encoding/json" - "log" - "os" - "time" -) - -// AccessLogJsonMiddleware produces the access log with records written as JSON. This middleware -// depends on TimerMiddleware and RecorderMiddleware that must be in the wrapped middlewares. It -// also uses request.Env["REMOTE_USER"].(string) set by the auth middlewares. -type AccessLogJsonMiddleware struct { - - // Logger points to the logger object used by this middleware, it defaults to - // log.New(os.Stderr, "", 0). - Logger *log.Logger -} - -// MiddlewareFunc makes AccessLogJsonMiddleware implement the Middleware interface. -func (mw *AccessLogJsonMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - // set the default Logger - if mw.Logger == nil { - mw.Logger = log.New(os.Stderr, "", 0) - } - - return func(w ResponseWriter, r *Request) { - - // call the handler - h(w, r) - - mw.Logger.Printf("%s", makeAccessLogJsonRecord(r).asJson()) - } -} - -// AccessLogJsonRecord is the data structure used by AccessLogJsonMiddleware to create the JSON -// records. (Public for documentation only, no public method uses it) -type AccessLogJsonRecord struct { - Timestamp *time.Time - StatusCode int - ResponseTime *time.Duration - HttpMethod string - RequestURI string - RemoteUser string - UserAgent string -} - -func makeAccessLogJsonRecord(r *Request) *AccessLogJsonRecord { - - var timestamp *time.Time - if r.Env["START_TIME"] != nil { - timestamp = r.Env["START_TIME"].(*time.Time) - } - - var statusCode int - if r.Env["STATUS_CODE"] != nil { - statusCode = r.Env["STATUS_CODE"].(int) - } - - var responseTime *time.Duration - if r.Env["ELAPSED_TIME"] != nil { - responseTime = r.Env["ELAPSED_TIME"].(*time.Duration) - } - - var remoteUser string - if r.Env["REMOTE_USER"] != nil { - remoteUser = r.Env["REMOTE_USER"].(string) - } - - return &AccessLogJsonRecord{ - Timestamp: timestamp, - StatusCode: statusCode, - ResponseTime: responseTime, - HttpMethod: r.Method, - RequestURI: r.URL.RequestURI(), - RemoteUser: remoteUser, - UserAgent: r.UserAgent(), - } -} - -func (r *AccessLogJsonRecord) asJson() []byte { - b, err := json.Marshal(r) - if err != nil { - panic(err) - } - return b -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/api.go b/vendor/github.com/ant0ine/go-json-rest/rest/api.go deleted file mode 100644 index 6295430..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/api.go +++ /dev/null @@ -1,83 +0,0 @@ -package rest - -import ( - "net/http" -) - -// Api defines a stack of Middlewares and an App. -type Api struct { - stack []Middleware - app App -} - -// NewApi makes a new Api object. The Middleware stack is empty, and the App is nil. -func NewApi() *Api { - return &Api{ - stack: []Middleware{}, - app: nil, - } -} - -// Use pushes one or multiple middlewares to the stack for middlewares -// maintained in the Api object. -func (api *Api) Use(middlewares ...Middleware) { - api.stack = append(api.stack, middlewares...) -} - -// SetApp sets the App in the Api object. -func (api *Api) SetApp(app App) { - api.app = app -} - -// MakeHandler wraps all the Middlewares of the stack and the App together, and returns an -// http.Handler ready to be used. If the Middleware stack is empty the App is used directly. If the -// App is nil, a HandlerFunc that does nothing is used instead. -func (api *Api) MakeHandler() http.Handler { - var appFunc HandlerFunc - if api.app != nil { - appFunc = api.app.AppFunc() - } else { - appFunc = func(w ResponseWriter, r *Request) {} - } - return http.HandlerFunc( - adapterFunc( - WrapMiddlewares(api.stack, appFunc), - ), - ) -} - -// Defines a stack of middlewares convenient for development. Among other things: -// console friendly logging, JSON indentation, error stack strace in the response. -var DefaultDevStack = []Middleware{ - &AccessLogApacheMiddleware{}, - &TimerMiddleware{}, - &RecorderMiddleware{}, - &PoweredByMiddleware{}, - &RecoverMiddleware{ - EnableResponseStackTrace: true, - }, - &JsonIndentMiddleware{}, - &ContentTypeCheckerMiddleware{}, -} - -// Defines a stack of middlewares convenient for production. Among other things: -// Apache CombinedLogFormat logging, gzip compression. -var DefaultProdStack = []Middleware{ - &AccessLogApacheMiddleware{ - Format: CombinedLogFormat, - }, - &TimerMiddleware{}, - &RecorderMiddleware{}, - &PoweredByMiddleware{}, - &RecoverMiddleware{}, - &GzipMiddleware{}, - &ContentTypeCheckerMiddleware{}, -} - -// Defines a stack of middlewares that should be common to most of the middleware stacks. -var DefaultCommonStack = []Middleware{ - &TimerMiddleware{}, - &RecorderMiddleware{}, - &PoweredByMiddleware{}, - &RecoverMiddleware{}, -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/auth_basic.go b/vendor/github.com/ant0ine/go-json-rest/rest/auth_basic.go deleted file mode 100644 index dbf254c..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/auth_basic.go +++ /dev/null @@ -1,100 +0,0 @@ -package rest - -import ( - "encoding/base64" - "errors" - "log" - "net/http" - "strings" -) - -// AuthBasicMiddleware provides a simple AuthBasic implementation. On failure, a 401 HTTP response -//is returned. On success, the wrapped middleware is called, and the userId is made available as -// request.Env["REMOTE_USER"].(string) -type AuthBasicMiddleware struct { - - // Realm name to display to the user. Required. - Realm string - - // Callback function that should perform the authentication of the user based on userId and - // password. Must return true on success, false on failure. Required. - Authenticator func(userId string, password string) bool - - // Callback function that should perform the authorization of the authenticated user. Called - // only after an authentication success. Must return true on success, false on failure. - // Optional, default to success. - Authorizator func(userId string, request *Request) bool -} - -// MiddlewareFunc makes AuthBasicMiddleware implement the Middleware interface. -func (mw *AuthBasicMiddleware) MiddlewareFunc(handler HandlerFunc) HandlerFunc { - - if mw.Realm == "" { - log.Fatal("Realm is required") - } - - if mw.Authenticator == nil { - log.Fatal("Authenticator is required") - } - - if mw.Authorizator == nil { - mw.Authorizator = func(userId string, request *Request) bool { - return true - } - } - - return func(writer ResponseWriter, request *Request) { - - authHeader := request.Header.Get("Authorization") - if authHeader == "" { - mw.unauthorized(writer) - return - } - - providedUserId, providedPassword, err := mw.decodeBasicAuthHeader(authHeader) - - if err != nil { - Error(writer, "Invalid authentication", http.StatusBadRequest) - return - } - - if !mw.Authenticator(providedUserId, providedPassword) { - mw.unauthorized(writer) - return - } - - if !mw.Authorizator(providedUserId, request) { - mw.unauthorized(writer) - return - } - - request.Env["REMOTE_USER"] = providedUserId - - handler(writer, request) - } -} - -func (mw *AuthBasicMiddleware) unauthorized(writer ResponseWriter) { - writer.Header().Set("WWW-Authenticate", "Basic realm="+mw.Realm) - Error(writer, "Not Authorized", http.StatusUnauthorized) -} - -func (mw *AuthBasicMiddleware) decodeBasicAuthHeader(header string) (user string, password string, err error) { - - parts := strings.SplitN(header, " ", 2) - if !(len(parts) == 2 && parts[0] == "Basic") { - return "", "", errors.New("Invalid authentication") - } - - decoded, err := base64.StdEncoding.DecodeString(parts[1]) - if err != nil { - return "", "", errors.New("Invalid base64") - } - - creds := strings.SplitN(string(decoded), ":", 2) - if len(creds) != 2 { - return "", "", errors.New("Invalid authentication") - } - - return creds[0], creds[1], nil -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/content_type_checker.go b/vendor/github.com/ant0ine/go-json-rest/rest/content_type_checker.go deleted file mode 100644 index 1d87877..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/content_type_checker.go +++ /dev/null @@ -1,40 +0,0 @@ -package rest - -import ( - "mime" - "net/http" - "strings" -) - -// ContentTypeCheckerMiddleware verifies the request Content-Type header and returns a -// StatusUnsupportedMediaType (415) HTTP error response if it's incorrect. The expected -// Content-Type is 'application/json' if the content is non-null. Note: If a charset parameter -// exists, it MUST be UTF-8. -type ContentTypeCheckerMiddleware struct{} - -// MiddlewareFunc makes ContentTypeCheckerMiddleware implement the Middleware interface. -func (mw *ContentTypeCheckerMiddleware) MiddlewareFunc(handler HandlerFunc) HandlerFunc { - - return func(w ResponseWriter, r *Request) { - - mediatype, params, _ := mime.ParseMediaType(r.Header.Get("Content-Type")) - charset, ok := params["charset"] - if !ok { - charset = "UTF-8" - } - - // per net/http doc, means that the length is known and non-null - if r.ContentLength > 0 && - !(mediatype == "application/json" && strings.ToUpper(charset) == "UTF-8") { - - Error(w, - "Bad Content-Type or charset, expected 'application/json'", - http.StatusUnsupportedMediaType, - ) - return - } - - // call the wrapped handler - handler(w, r) - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/cors.go b/vendor/github.com/ant0ine/go-json-rest/rest/cors.go deleted file mode 100644 index 5b00543..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/cors.go +++ /dev/null @@ -1,135 +0,0 @@ -package rest - -import ( - "net/http" - "strconv" - "strings" -) - -// Possible improvements: -// If AllowedMethods["*"] then Access-Control-Allow-Methods is set to the requested methods -// If AllowedHeaderss["*"] then Access-Control-Allow-Headers is set to the requested headers -// Put some presets in AllowedHeaders -// Put some presets in AccessControlExposeHeaders - -// CorsMiddleware provides a configurable CORS implementation. -type CorsMiddleware struct { - allowedMethods map[string]bool - allowedMethodsCsv string - allowedHeaders map[string]bool - allowedHeadersCsv string - - // Reject non CORS requests if true. See CorsInfo.IsCors. - RejectNonCorsRequests bool - - // Function excecuted for every CORS requests to validate the Origin. (Required) - // Must return true if valid, false if invalid. - // For instance: simple equality, regexp, DB lookup, ... - OriginValidator func(origin string, request *Request) bool - - // List of allowed HTTP methods. Note that the comparison will be made in - // uppercase to avoid common mistakes. And that the - // Access-Control-Allow-Methods response header also uses uppercase. - // (see CorsInfo.AccessControlRequestMethod) - AllowedMethods []string - - // List of allowed HTTP Headers. Note that the comparison will be made with - // noarmalized names (http.CanonicalHeaderKey). And that the response header - // also uses normalized names. - // (see CorsInfo.AccessControlRequestHeaders) - AllowedHeaders []string - - // List of headers used to set the Access-Control-Expose-Headers header. - AccessControlExposeHeaders []string - - // User to se the Access-Control-Allow-Credentials response header. - AccessControlAllowCredentials bool - - // Used to set the Access-Control-Max-Age response header, in seconds. - AccessControlMaxAge int -} - -// MiddlewareFunc makes CorsMiddleware implement the Middleware interface. -func (mw *CorsMiddleware) MiddlewareFunc(handler HandlerFunc) HandlerFunc { - - // precompute as much as possible at init time - - mw.allowedMethods = map[string]bool{} - normedMethods := []string{} - for _, allowedMethod := range mw.AllowedMethods { - normed := strings.ToUpper(allowedMethod) - mw.allowedMethods[normed] = true - normedMethods = append(normedMethods, normed) - } - mw.allowedMethodsCsv = strings.Join(normedMethods, ",") - - mw.allowedHeaders = map[string]bool{} - normedHeaders := []string{} - for _, allowedHeader := range mw.AllowedHeaders { - normed := http.CanonicalHeaderKey(allowedHeader) - mw.allowedHeaders[normed] = true - normedHeaders = append(normedHeaders, normed) - } - mw.allowedHeadersCsv = strings.Join(normedHeaders, ",") - - return func(writer ResponseWriter, request *Request) { - - corsInfo := request.GetCorsInfo() - - // non CORS requests - if !corsInfo.IsCors { - if mw.RejectNonCorsRequests { - Error(writer, "Non CORS request", http.StatusForbidden) - return - } - // continue, execute the wrapped middleware - handler(writer, request) - return - } - - // Validate the Origin - if mw.OriginValidator(corsInfo.Origin, request) == false { - Error(writer, "Invalid Origin", http.StatusForbidden) - return - } - - if corsInfo.IsPreflight { - - // check the request methods - if mw.allowedMethods[corsInfo.AccessControlRequestMethod] == false { - Error(writer, "Invalid Preflight Request", http.StatusForbidden) - return - } - - // check the request headers - for _, requestedHeader := range corsInfo.AccessControlRequestHeaders { - if mw.allowedHeaders[requestedHeader] == false { - Error(writer, "Invalid Preflight Request", http.StatusForbidden) - return - } - } - - writer.Header().Set("Access-Control-Allow-Methods", mw.allowedMethodsCsv) - writer.Header().Set("Access-Control-Allow-Headers", mw.allowedHeadersCsv) - writer.Header().Set("Access-Control-Allow-Origin", corsInfo.Origin) - if mw.AccessControlAllowCredentials == true { - writer.Header().Set("Access-Control-Allow-Credentials", "true") - } - writer.Header().Set("Access-Control-Max-Age", strconv.Itoa(mw.AccessControlMaxAge)) - writer.WriteHeader(http.StatusOK) - return - } - - // Non-preflight requests - for _, exposed := range mw.AccessControlExposeHeaders { - writer.Header().Add("Access-Control-Expose-Headers", exposed) - } - writer.Header().Set("Access-Control-Allow-Origin", corsInfo.Origin) - if mw.AccessControlAllowCredentials == true { - writer.Header().Set("Access-Control-Allow-Credentials", "true") - } - // continure, execute the wrapped middleware - handler(writer, request) - return - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/doc.go b/vendor/github.com/ant0ine/go-json-rest/rest/doc.go deleted file mode 100644 index fa6f5b2..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/doc.go +++ /dev/null @@ -1,47 +0,0 @@ -// A quick and easy way to setup a RESTful JSON API -// -// http://ant0ine.github.io/go-json-rest/ -// -// Go-Json-Rest is a thin layer on top of net/http that helps building RESTful JSON APIs easily. -// It provides fast and scalable request routing using a Trie based implementation, helpers to deal -// with JSON requests and responses, and middlewares for functionalities like CORS, Auth, Gzip, -// Status, ... -// -// Example: -// -// package main -// -// import ( -// "github.com/ant0ine/go-json-rest/rest" -// "log" -// "net/http" -// ) -// -// type User struct { -// Id string -// Name string -// } -// -// func GetUser(w rest.ResponseWriter, req *rest.Request) { -// user := User{ -// Id: req.PathParam("id"), -// Name: "Antoine", -// } -// w.WriteJson(&user) -// } -// -// func main() { -// api := rest.NewApi() -// api.Use(rest.DefaultDevStack...) -// router, err := rest.MakeRouter( -// rest.Get("/users/:id", GetUser), -// ) -// if err != nil { -// log.Fatal(err) -// } -// api.SetApp(router) -// log.Fatal(http.ListenAndServe(":8080", api.MakeHandler())) -// } -// -// -package rest diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/gzip.go b/vendor/github.com/ant0ine/go-json-rest/rest/gzip.go deleted file mode 100644 index 0fafc05..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/gzip.go +++ /dev/null @@ -1,132 +0,0 @@ -package rest - -import ( - "bufio" - "compress/gzip" - "net" - "net/http" - "strings" -) - -// GzipMiddleware is responsible for compressing the payload with gzip and setting the proper -// headers when supported by the client. It must be wrapped by TimerMiddleware for the -// compression time to be captured. And It must be wrapped by RecorderMiddleware for the -// compressed BYTES_WRITTEN to be captured. -type GzipMiddleware struct{} - -// MiddlewareFunc makes GzipMiddleware implement the Middleware interface. -func (mw *GzipMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - return func(w ResponseWriter, r *Request) { - // gzip support enabled - canGzip := strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") - // client accepts gzip ? - writer := &gzipResponseWriter{w, false, canGzip, nil} - defer func() { - // need to close gzip writer - if writer.gzipWriter != nil { - writer.gzipWriter.Close() - } - }() - // call the handler with the wrapped writer - h(writer, r) - } -} - -// Private responseWriter intantiated by the gzip middleware. -// It encodes the payload with gzip and set the proper headers. -// It implements the following interfaces: -// ResponseWriter -// http.ResponseWriter -// http.Flusher -// http.CloseNotifier -// http.Hijacker -type gzipResponseWriter struct { - ResponseWriter - wroteHeader bool - canGzip bool - gzipWriter *gzip.Writer -} - -// Set the right headers for gzip encoded responses. -func (w *gzipResponseWriter) WriteHeader(code int) { - - // Always set the Vary header, even if this particular request - // is not gzipped. - w.Header().Add("Vary", "Accept-Encoding") - - if w.canGzip { - w.Header().Set("Content-Encoding", "gzip") - } - - w.ResponseWriter.WriteHeader(code) - w.wroteHeader = true -} - -// Make sure the local Write is called. -func (w *gzipResponseWriter) WriteJson(v interface{}) error { - b, err := w.EncodeJson(v) - if err != nil { - return err - } - _, err = w.Write(b) - if err != nil { - return err - } - return nil -} - -// Make sure the local WriteHeader is called, and call the parent Flush. -// Provided in order to implement the http.Flusher interface. -func (w *gzipResponseWriter) Flush() { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - flusher := w.ResponseWriter.(http.Flusher) - flusher.Flush() -} - -// Call the parent CloseNotify. -// Provided in order to implement the http.CloseNotifier interface. -func (w *gzipResponseWriter) CloseNotify() <-chan bool { - notifier := w.ResponseWriter.(http.CloseNotifier) - return notifier.CloseNotify() -} - -// Provided in order to implement the http.Hijacker interface. -func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker := w.ResponseWriter.(http.Hijacker) - return hijacker.Hijack() -} - -// Make sure the local WriteHeader is called, and encode the payload if necessary. -// Provided in order to implement the http.ResponseWriter interface. -func (w *gzipResponseWriter) Write(b []byte) (int, error) { - - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - - writer := w.ResponseWriter.(http.ResponseWriter) - - if w.canGzip { - // Write can be called multiple times for a given response. - // (see the streaming example: - // https://github.com/ant0ine/go-json-rest-examples/tree/master/streaming) - // The gzipWriter is instantiated only once, and flushed after - // each write. - if w.gzipWriter == nil { - w.gzipWriter = gzip.NewWriter(writer) - } - count, errW := w.gzipWriter.Write(b) - errF := w.gzipWriter.Flush() - if errW != nil { - return count, errW - } - if errF != nil { - return count, errF - } - return count, nil - } - - return writer.Write(b) -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/if.go b/vendor/github.com/ant0ine/go-json-rest/rest/if.go deleted file mode 100644 index daa37d1..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/if.go +++ /dev/null @@ -1,53 +0,0 @@ -package rest - -import ( - "log" -) - -// IfMiddleware evaluates at runtime a condition based on the current request, and decides to -// execute one of the other Middleware based on this boolean. -type IfMiddleware struct { - - // Runtime condition that decides of the execution of IfTrue of IfFalse. - Condition func(r *Request) bool - - // Middleware to run when the condition is true. Note that the middleware is initialized - // weather if will be used or not. (Optional, pass-through if not set) - IfTrue Middleware - - // Middleware to run when the condition is false. Note that the middleware is initialized - // weather if will be used or not. (Optional, pass-through if not set) - IfFalse Middleware -} - -// MiddlewareFunc makes TimerMiddleware implement the Middleware interface. -func (mw *IfMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - if mw.Condition == nil { - log.Fatal("IfMiddleware Condition is required") - } - - var ifTrueHandler HandlerFunc - if mw.IfTrue != nil { - ifTrueHandler = mw.IfTrue.MiddlewareFunc(h) - } else { - ifTrueHandler = h - } - - var ifFalseHandler HandlerFunc - if mw.IfFalse != nil { - ifFalseHandler = mw.IfFalse.MiddlewareFunc(h) - } else { - ifFalseHandler = h - } - - return func(w ResponseWriter, r *Request) { - - if mw.Condition(r) { - ifTrueHandler(w, r) - } else { - ifFalseHandler(w, r) - } - - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/json_indent.go b/vendor/github.com/ant0ine/go-json-rest/rest/json_indent.go deleted file mode 100644 index ad9a5ca..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/json_indent.go +++ /dev/null @@ -1,113 +0,0 @@ -package rest - -import ( - "bufio" - "encoding/json" - "net" - "net/http" -) - -// JsonIndentMiddleware provides JSON encoding with indentation. -// It could be convenient to use it during development. -// It works by "subclassing" the responseWriter provided by the wrapping middleware, -// replacing the writer.EncodeJson and writer.WriteJson implementations, -// and making the parent implementations ignored. -type JsonIndentMiddleware struct { - - // prefix string, as in json.MarshalIndent - Prefix string - - // indentation string, as in json.MarshalIndent - Indent string -} - -// MiddlewareFunc makes JsonIndentMiddleware implement the Middleware interface. -func (mw *JsonIndentMiddleware) MiddlewareFunc(handler HandlerFunc) HandlerFunc { - - if mw.Indent == "" { - mw.Indent = " " - } - - return func(w ResponseWriter, r *Request) { - - writer := &jsonIndentResponseWriter{w, false, mw.Prefix, mw.Indent} - // call the wrapped handler - handler(writer, r) - } -} - -// Private responseWriter intantiated by the middleware. -// It implements the following interfaces: -// ResponseWriter -// http.ResponseWriter -// http.Flusher -// http.CloseNotifier -// http.Hijacker -type jsonIndentResponseWriter struct { - ResponseWriter - wroteHeader bool - prefix string - indent string -} - -// Replace the parent EncodeJson to provide indentation. -func (w *jsonIndentResponseWriter) EncodeJson(v interface{}) ([]byte, error) { - b, err := json.MarshalIndent(v, w.prefix, w.indent) - if err != nil { - return nil, err - } - return b, nil -} - -// Make sure the local EncodeJson and local Write are called. -// Does not call the parent WriteJson. -func (w *jsonIndentResponseWriter) WriteJson(v interface{}) error { - b, err := w.EncodeJson(v) - if err != nil { - return err - } - _, err = w.Write(b) - if err != nil { - return err - } - return nil -} - -// Call the parent WriteHeader. -func (w *jsonIndentResponseWriter) WriteHeader(code int) { - w.ResponseWriter.WriteHeader(code) - w.wroteHeader = true -} - -// Make sure the local WriteHeader is called, and call the parent Flush. -// Provided in order to implement the http.Flusher interface. -func (w *jsonIndentResponseWriter) Flush() { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - flusher := w.ResponseWriter.(http.Flusher) - flusher.Flush() -} - -// Call the parent CloseNotify. -// Provided in order to implement the http.CloseNotifier interface. -func (w *jsonIndentResponseWriter) CloseNotify() <-chan bool { - notifier := w.ResponseWriter.(http.CloseNotifier) - return notifier.CloseNotify() -} - -// Provided in order to implement the http.Hijacker interface. -func (w *jsonIndentResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker := w.ResponseWriter.(http.Hijacker) - return hijacker.Hijack() -} - -// Make sure the local WriteHeader is called, and call the parent Write. -// Provided in order to implement the http.ResponseWriter interface. -func (w *jsonIndentResponseWriter) Write(b []byte) (int, error) { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - writer := w.ResponseWriter.(http.ResponseWriter) - return writer.Write(b) -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/jsonp.go b/vendor/github.com/ant0ine/go-json-rest/rest/jsonp.go deleted file mode 100644 index 6071b50..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/jsonp.go +++ /dev/null @@ -1,116 +0,0 @@ -package rest - -import ( - "bufio" - "net" - "net/http" -) - -// JsonpMiddleware provides JSONP responses on demand, based on the presence -// of a query string argument specifying the callback name. -type JsonpMiddleware struct { - - // Name of the query string parameter used to specify the - // the name of the JS callback used for the padding. - // Defaults to "callback". - CallbackNameKey string -} - -// MiddlewareFunc returns a HandlerFunc that implements the middleware. -func (mw *JsonpMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - if mw.CallbackNameKey == "" { - mw.CallbackNameKey = "callback" - } - - return func(w ResponseWriter, r *Request) { - - callbackName := r.URL.Query().Get(mw.CallbackNameKey) - // TODO validate the callbackName ? - - if callbackName != "" { - // the client request JSONP, instantiate JsonpMiddleware. - writer := &jsonpResponseWriter{w, false, callbackName} - // call the handler with the wrapped writer - h(writer, r) - } else { - // do nothing special - h(w, r) - } - - } -} - -// Private responseWriter intantiated by the JSONP middleware. -// It adds the padding to the payload and set the proper headers. -// It implements the following interfaces: -// ResponseWriter -// http.ResponseWriter -// http.Flusher -// http.CloseNotifier -// http.Hijacker -type jsonpResponseWriter struct { - ResponseWriter - wroteHeader bool - callbackName string -} - -// Overwrite the Content-Type to be text/javascript -func (w *jsonpResponseWriter) WriteHeader(code int) { - - w.Header().Set("Content-Type", "text/javascript") - - w.ResponseWriter.WriteHeader(code) - w.wroteHeader = true -} - -// Make sure the local Write is called. -func (w *jsonpResponseWriter) WriteJson(v interface{}) error { - b, err := w.EncodeJson(v) - if err != nil { - return err - } - // JSONP security fix (http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/) - w.Header().Set("Content-Disposition", "filename=f.txt") - w.Header().Set("X-Content-Type-Options", "nosniff") - w.Write([]byte("/**/" + w.callbackName + "(")) - w.Write(b) - w.Write([]byte(")")) - return nil -} - -// Make sure the local WriteHeader is called, and call the parent Flush. -// Provided in order to implement the http.Flusher interface. -func (w *jsonpResponseWriter) Flush() { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - flusher := w.ResponseWriter.(http.Flusher) - flusher.Flush() -} - -// Call the parent CloseNotify. -// Provided in order to implement the http.CloseNotifier interface. -func (w *jsonpResponseWriter) CloseNotify() <-chan bool { - notifier := w.ResponseWriter.(http.CloseNotifier) - return notifier.CloseNotify() -} - -// Provided in order to implement the http.Hijacker interface. -func (w *jsonpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker := w.ResponseWriter.(http.Hijacker) - return hijacker.Hijack() -} - -// Make sure the local WriteHeader is called. -// Provided in order to implement the http.ResponseWriter interface. -func (w *jsonpResponseWriter) Write(b []byte) (int, error) { - - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - - writer := w.ResponseWriter.(http.ResponseWriter) - - return writer.Write(b) -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/middleware.go b/vendor/github.com/ant0ine/go-json-rest/rest/middleware.go deleted file mode 100644 index ba03fb8..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/middleware.go +++ /dev/null @@ -1,72 +0,0 @@ -package rest - -import ( - "net/http" -) - -// HandlerFunc defines the handler function. It is the go-json-rest equivalent of http.HandlerFunc. -type HandlerFunc func(ResponseWriter, *Request) - -// App defines the interface that an object should implement to be used as an app in this framework -// stack. The App is the top element of the stack, the other elements being middlewares. -type App interface { - AppFunc() HandlerFunc -} - -// AppSimple is an adapter type that makes it easy to write an App with a simple function. -// eg: rest.NewApi(rest.AppSimple(func(w rest.ResponseWriter, r *rest.Request) { ... })) -type AppSimple HandlerFunc - -// AppFunc makes AppSimple implement the App interface. -func (as AppSimple) AppFunc() HandlerFunc { - return HandlerFunc(as) -} - -// Middleware defines the interface that objects must implement in order to wrap a HandlerFunc and -// be used in the middleware stack. -type Middleware interface { - MiddlewareFunc(handler HandlerFunc) HandlerFunc -} - -// MiddlewareSimple is an adapter type that makes it easy to write a Middleware with a simple -// function. eg: api.Use(rest.MiddlewareSimple(func(h HandlerFunc) Handlerfunc { ... })) -type MiddlewareSimple func(handler HandlerFunc) HandlerFunc - -// MiddlewareFunc makes MiddlewareSimple implement the Middleware interface. -func (ms MiddlewareSimple) MiddlewareFunc(handler HandlerFunc) HandlerFunc { - return ms(handler) -} - -// WrapMiddlewares calls the MiddlewareFunc methods in the reverse order and returns an HandlerFunc -// ready to be executed. This can be used to wrap a set of middlewares, post routing, on a per Route -// basis. -func WrapMiddlewares(middlewares []Middleware, handler HandlerFunc) HandlerFunc { - wrapped := handler - for i := len(middlewares) - 1; i >= 0; i-- { - wrapped = middlewares[i].MiddlewareFunc(wrapped) - } - return wrapped -} - -// Handle the transition between net/http and go-json-rest objects. -// It intanciates the rest.Request and rest.ResponseWriter, ... -func adapterFunc(handler HandlerFunc) http.HandlerFunc { - - return func(origWriter http.ResponseWriter, origRequest *http.Request) { - - // instantiate the rest objects - request := &Request{ - origRequest, - nil, - map[string]interface{}{}, - } - - writer := &responseWriter{ - origWriter, - false, - } - - // call the wrapped handler - handler(writer, request) - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/powered_by.go b/vendor/github.com/ant0ine/go-json-rest/rest/powered_by.go deleted file mode 100644 index 3b22ccf..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/powered_by.go +++ /dev/null @@ -1,29 +0,0 @@ -package rest - -const xPoweredByDefault = "go-json-rest" - -// PoweredByMiddleware adds the "X-Powered-By" header to the HTTP response. -type PoweredByMiddleware struct { - - // If specified, used as the value for the "X-Powered-By" response header. - // Defaults to "go-json-rest". - XPoweredBy string -} - -// MiddlewareFunc makes PoweredByMiddleware implement the Middleware interface. -func (mw *PoweredByMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - poweredBy := xPoweredByDefault - if mw.XPoweredBy != "" { - poweredBy = mw.XPoweredBy - } - - return func(w ResponseWriter, r *Request) { - - w.Header().Add("X-Powered-By", poweredBy) - - // call the handler - h(w, r) - - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/recorder.go b/vendor/github.com/ant0ine/go-json-rest/rest/recorder.go deleted file mode 100644 index 20502e9..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/recorder.go +++ /dev/null @@ -1,100 +0,0 @@ -package rest - -import ( - "bufio" - "net" - "net/http" -) - -// RecorderMiddleware keeps a record of the HTTP status code of the response, -// and the number of bytes written. -// The result is available to the wrapping handlers as request.Env["STATUS_CODE"].(int), -// and as request.Env["BYTES_WRITTEN"].(int64) -type RecorderMiddleware struct{} - -// MiddlewareFunc makes RecorderMiddleware implement the Middleware interface. -func (mw *RecorderMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - return func(w ResponseWriter, r *Request) { - - writer := &recorderResponseWriter{w, 0, false, 0} - - // call the handler - h(writer, r) - - r.Env["STATUS_CODE"] = writer.statusCode - r.Env["BYTES_WRITTEN"] = writer.bytesWritten - } -} - -// Private responseWriter intantiated by the recorder middleware. -// It keeps a record of the HTTP status code of the response. -// It implements the following interfaces: -// ResponseWriter -// http.ResponseWriter -// http.Flusher -// http.CloseNotifier -// http.Hijacker -type recorderResponseWriter struct { - ResponseWriter - statusCode int - wroteHeader bool - bytesWritten int64 -} - -// Record the status code. -func (w *recorderResponseWriter) WriteHeader(code int) { - w.ResponseWriter.WriteHeader(code) - if w.wroteHeader { - return - } - w.statusCode = code - w.wroteHeader = true -} - -// Make sure the local Write is called. -func (w *recorderResponseWriter) WriteJson(v interface{}) error { - b, err := w.EncodeJson(v) - if err != nil { - return err - } - _, err = w.Write(b) - if err != nil { - return err - } - return nil -} - -// Make sure the local WriteHeader is called, and call the parent Flush. -// Provided in order to implement the http.Flusher interface. -func (w *recorderResponseWriter) Flush() { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - flusher := w.ResponseWriter.(http.Flusher) - flusher.Flush() -} - -// Call the parent CloseNotify. -// Provided in order to implement the http.CloseNotifier interface. -func (w *recorderResponseWriter) CloseNotify() <-chan bool { - notifier := w.ResponseWriter.(http.CloseNotifier) - return notifier.CloseNotify() -} - -// Provided in order to implement the http.Hijacker interface. -func (w *recorderResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker := w.ResponseWriter.(http.Hijacker) - return hijacker.Hijack() -} - -// Make sure the local WriteHeader is called, and call the parent Write. -// Provided in order to implement the http.ResponseWriter interface. -func (w *recorderResponseWriter) Write(b []byte) (int, error) { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - writer := w.ResponseWriter.(http.ResponseWriter) - written, err := writer.Write(b) - w.bytesWritten += int64(written) - return written, err -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/recover.go b/vendor/github.com/ant0ine/go-json-rest/rest/recover.go deleted file mode 100644 index 99f1515..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/recover.go +++ /dev/null @@ -1,74 +0,0 @@ -package rest - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "os" - "runtime/debug" -) - -// RecoverMiddleware catches the panic errors that occur in the wrapped HandleFunc, -// and convert them to 500 responses. -type RecoverMiddleware struct { - - // Custom logger used for logging the panic errors, - // optional, defaults to log.New(os.Stderr, "", 0) - Logger *log.Logger - - // If true, the log records will be printed as JSON. Convenient for log parsing. - EnableLogAsJson bool - - // If true, when a "panic" happens, the error string and the stack trace will be - // printed in the 500 response body. - EnableResponseStackTrace bool -} - -// MiddlewareFunc makes RecoverMiddleware implement the Middleware interface. -func (mw *RecoverMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - // set the default Logger - if mw.Logger == nil { - mw.Logger = log.New(os.Stderr, "", 0) - } - - return func(w ResponseWriter, r *Request) { - - // catch user code's panic, and convert to http response - defer func() { - if reco := recover(); reco != nil { - trace := debug.Stack() - - // log the trace - message := fmt.Sprintf("%s\n%s", reco, trace) - mw.logError(message) - - // write error response - if mw.EnableResponseStackTrace { - Error(w, message, http.StatusInternalServerError) - } else { - Error(w, "Internal Server Error", http.StatusInternalServerError) - } - } - }() - - // call the handler - h(w, r) - } -} - -func (mw *RecoverMiddleware) logError(message string) { - if mw.EnableLogAsJson { - record := map[string]string{ - "error": message, - } - b, err := json.Marshal(&record) - if err != nil { - panic(err) - } - mw.Logger.Printf("%s", b) - } else { - mw.Logger.Print(message) - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/request.go b/vendor/github.com/ant0ine/go-json-rest/rest/request.go deleted file mode 100644 index c4eb381..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/request.go +++ /dev/null @@ -1,148 +0,0 @@ -package rest - -import ( - "encoding/json" - "errors" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -var ( - // ErrJsonPayloadEmpty is returned when the JSON payload is empty. - ErrJsonPayloadEmpty = errors.New("JSON payload is empty") -) - -// Request inherits from http.Request, and provides additional methods. -type Request struct { - *http.Request - - // Map of parameters that have been matched in the URL Path. - PathParams map[string]string - - // Environment used by middlewares to communicate. - Env map[string]interface{} -} - -// PathParam provides a convenient access to the PathParams map. -func (r *Request) PathParam(name string) string { - return r.PathParams[name] -} - -// DecodeJsonPayload reads the request body and decodes the JSON using json.Unmarshal. -func (r *Request) DecodeJsonPayload(v interface{}) error { - content, err := ioutil.ReadAll(r.Body) - r.Body.Close() - if err != nil { - return err - } - if len(content) == 0 { - return ErrJsonPayloadEmpty - } - err = json.Unmarshal(content, v) - if err != nil { - return err - } - return nil -} - -// BaseUrl returns a new URL object with the Host and Scheme taken from the request. -// (without the trailing slash in the host) -func (r *Request) BaseUrl() *url.URL { - scheme := r.URL.Scheme - if scheme == "" { - scheme = "http" - } - - // HTTP sometimes gives the default scheme as HTTP even when used with TLS - // Check if TLS is not nil and given back https scheme - if scheme == "http" && r.TLS != nil { - scheme = "https" - } - - host := r.Host - if len(host) > 0 && host[len(host)-1] == '/' { - host = host[:len(host)-1] - } - - return &url.URL{ - Scheme: scheme, - Host: host, - } -} - -// UrlFor returns the URL object from UriBase with the Path set to path, and the query -// string built with queryParams. -func (r *Request) UrlFor(path string, queryParams map[string][]string) *url.URL { - baseUrl := r.BaseUrl() - baseUrl.Path = path - if queryParams != nil { - query := url.Values{} - for k, v := range queryParams { - for _, vv := range v { - query.Add(k, vv) - } - } - baseUrl.RawQuery = query.Encode() - } - return baseUrl -} - -// CorsInfo contains the CORS request info derived from a rest.Request. -type CorsInfo struct { - IsCors bool - IsPreflight bool - Origin string - OriginUrl *url.URL - - // The header value is converted to uppercase to avoid common mistakes. - AccessControlRequestMethod string - - // The header values are normalized with http.CanonicalHeaderKey. - AccessControlRequestHeaders []string -} - -// GetCorsInfo derives CorsInfo from Request. -func (r *Request) GetCorsInfo() *CorsInfo { - - origin := r.Header.Get("Origin") - - var originUrl *url.URL - var isCors bool - - if origin == "" { - isCors = false - } else if origin == "null" { - isCors = true - } else { - var err error - originUrl, err = url.ParseRequestURI(origin) - isCors = err == nil && r.Host != originUrl.Host - } - - reqMethod := r.Header.Get("Access-Control-Request-Method") - - reqHeaders := []string{} - rawReqHeaders := r.Header[http.CanonicalHeaderKey("Access-Control-Request-Headers")] - for _, rawReqHeader := range rawReqHeaders { - if len(rawReqHeader) == 0 { - continue - } - // net/http does not handle comma delimited headers for us - for _, reqHeader := range strings.Split(rawReqHeader, ",") { - reqHeaders = append(reqHeaders, http.CanonicalHeaderKey(strings.TrimSpace(reqHeader))) - } - } - - isPreflight := isCors && r.Method == "OPTIONS" && reqMethod != "" - - return &CorsInfo{ - IsCors: isCors, - IsPreflight: isPreflight, - Origin: origin, - OriginUrl: originUrl, - AccessControlRequestMethod: strings.ToUpper(reqMethod), - AccessControlRequestHeaders: reqHeaders, - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/response.go b/vendor/github.com/ant0ine/go-json-rest/rest/response.go deleted file mode 100644 index 52529f1..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/response.go +++ /dev/null @@ -1,127 +0,0 @@ -package rest - -import ( - "bufio" - "encoding/json" - "net" - "net/http" -) - -// A ResponseWriter interface dedicated to JSON HTTP response. -// Note, the responseWriter object instantiated by the framework also implements many other interfaces -// accessible by type assertion: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker. -type ResponseWriter interface { - - // Identical to the http.ResponseWriter interface - Header() http.Header - - // Use EncodeJson to generate the payload, write the headers with http.StatusOK if - // they are not already written, then write the payload. - // The Content-Type header is set to "application/json", unless already specified. - WriteJson(v interface{}) error - - // Encode the data structure to JSON, mainly used to wrap ResponseWriter in - // middlewares. - EncodeJson(v interface{}) ([]byte, error) - - // Similar to the http.ResponseWriter interface, with additional JSON related - // headers set. - WriteHeader(int) -} - -// This allows to customize the field name used in the error response payload. -// It defaults to "Error" for compatibility reason, but can be changed before starting the server. -// eg: rest.ErrorFieldName = "errorMessage" -var ErrorFieldName = "Error" - -// Error produces an error response in JSON with the following structure, '{"Error":"My error message"}' -// The standard plain text net/http Error helper can still be called like this: -// http.Error(w, "error message", code) -func Error(w ResponseWriter, error string, code int) { - w.WriteHeader(code) - err := w.WriteJson(map[string]string{ErrorFieldName: error}) - if err != nil { - panic(err) - } -} - -// NotFound produces a 404 response with the following JSON, '{"Error":"Resource not found"}' -// The standard plain text net/http NotFound helper can still be called like this: -// http.NotFound(w, r.Request) -func NotFound(w ResponseWriter, r *Request) { - Error(w, "Resource not found", http.StatusNotFound) -} - -// Private responseWriter intantiated by the resource handler. -// It implements the following interfaces: -// ResponseWriter -// http.ResponseWriter -// http.Flusher -// http.CloseNotifier -// http.Hijacker -type responseWriter struct { - http.ResponseWriter - wroteHeader bool -} - -func (w *responseWriter) WriteHeader(code int) { - if w.Header().Get("Content-Type") == "" { - // Per spec, UTF-8 is the default, and the charset parameter should not - // be necessary. But some clients (eg: Chrome) think otherwise. - // Since json.Marshal produces UTF-8, setting the charset parameter is a - // safe option. - w.Header().Set("Content-Type", "application/json; charset=utf-8") - } - w.ResponseWriter.WriteHeader(code) - w.wroteHeader = true -} - -func (w *responseWriter) EncodeJson(v interface{}) ([]byte, error) { - b, err := json.Marshal(v) - if err != nil { - return nil, err - } - return b, nil -} - -// Encode the object in JSON and call Write. -func (w *responseWriter) WriteJson(v interface{}) error { - b, err := w.EncodeJson(v) - if err != nil { - return err - } - _, err = w.Write(b) - if err != nil { - return err - } - return nil -} - -// Provided in order to implement the http.ResponseWriter interface. -func (w *responseWriter) Write(b []byte) (int, error) { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - return w.ResponseWriter.Write(b) -} - -// Provided in order to implement the http.Flusher interface. -func (w *responseWriter) Flush() { - if !w.wroteHeader { - w.WriteHeader(http.StatusOK) - } - flusher := w.ResponseWriter.(http.Flusher) - flusher.Flush() -} - -// Provided in order to implement the http.CloseNotifier interface. -func (w *responseWriter) CloseNotify() <-chan bool { - notifier := w.ResponseWriter.(http.CloseNotifier) - return notifier.CloseNotify() -} - -// Provided in order to implement the http.Hijacker interface. -func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker := w.ResponseWriter.(http.Hijacker) - return hijacker.Hijack() -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/route.go b/vendor/github.com/ant0ine/go-json-rest/rest/route.go deleted file mode 100644 index efb94a7..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/route.go +++ /dev/null @@ -1,107 +0,0 @@ -package rest - -import ( - "strings" -) - -// Route defines a route as consumed by the router. It can be instantiated directly, or using one -// of the shortcut methods: rest.Get, rest.Post, rest.Put, rest.Patch and rest.Delete. -type Route struct { - - // Any HTTP method. It will be used as uppercase to avoid common mistakes. - HttpMethod string - - // A string like "/resource/:id.json". - // Placeholders supported are: - // :paramName that matches any char to the first '/' or '.' - // #paramName that matches any char to the first '/' - // *paramName that matches everything to the end of the string - // (placeholder names must be unique per PathExp) - PathExp string - - // Code that will be executed when this route is taken. - Func HandlerFunc -} - -// MakePath generates the path corresponding to this Route and the provided path parameters. -// This is used for reverse route resolution. -func (route *Route) MakePath(pathParams map[string]string) string { - path := route.PathExp - for paramName, paramValue := range pathParams { - paramPlaceholder := ":" + paramName - relaxedPlaceholder := "#" + paramName - splatPlaceholder := "*" + paramName - r := strings.NewReplacer(paramPlaceholder, paramValue, splatPlaceholder, paramValue, relaxedPlaceholder, paramValue) - path = r.Replace(path) - } - return path -} - -// Head is a shortcut method that instantiates a HEAD route. See the Route object the parameters definitions. -// Equivalent to &Route{"HEAD", pathExp, handlerFunc} -func Head(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "HEAD", - PathExp: pathExp, - Func: handlerFunc, - } -} - -// Get is a shortcut method that instantiates a GET route. See the Route object the parameters definitions. -// Equivalent to &Route{"GET", pathExp, handlerFunc} -func Get(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "GET", - PathExp: pathExp, - Func: handlerFunc, - } -} - -// Post is a shortcut method that instantiates a POST route. See the Route object the parameters definitions. -// Equivalent to &Route{"POST", pathExp, handlerFunc} -func Post(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "POST", - PathExp: pathExp, - Func: handlerFunc, - } -} - -// Put is a shortcut method that instantiates a PUT route. See the Route object the parameters definitions. -// Equivalent to &Route{"PUT", pathExp, handlerFunc} -func Put(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "PUT", - PathExp: pathExp, - Func: handlerFunc, - } -} - -// Patch is a shortcut method that instantiates a PATCH route. See the Route object the parameters definitions. -// Equivalent to &Route{"PATCH", pathExp, handlerFunc} -func Patch(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "PATCH", - PathExp: pathExp, - Func: handlerFunc, - } -} - -// Delete is a shortcut method that instantiates a DELETE route. Equivalent to &Route{"DELETE", pathExp, handlerFunc} -func Delete(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "DELETE", - PathExp: pathExp, - Func: handlerFunc, - } -} - -// Options is a shortcut method that instantiates an OPTIONS route. See the Route object the parameters definitions. -// Equivalent to &Route{"OPTIONS", pathExp, handlerFunc} -func Options(pathExp string, handlerFunc HandlerFunc) *Route { - return &Route{ - HttpMethod: "OPTIONS", - PathExp: pathExp, - Func: handlerFunc, - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/router.go b/vendor/github.com/ant0ine/go-json-rest/rest/router.go deleted file mode 100644 index f7ab713..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/router.go +++ /dev/null @@ -1,194 +0,0 @@ -package rest - -import ( - "errors" - "github.com/ant0ine/go-json-rest/rest/trie" - "net/http" - "net/url" - "strings" -) - -type router struct { - Routes []*Route - - disableTrieCompression bool - index map[*Route]int - trie *trie.Trie -} - -// MakeRouter returns the router app. Given a set of Routes, it dispatches the request to the -// HandlerFunc of the first route that matches. The order of the Routes matters. -func MakeRouter(routes ...*Route) (App, error) { - r := &router{ - Routes: routes, - } - err := r.start() - if err != nil { - return nil, err - } - return r, nil -} - -// Handle the REST routing and run the user code. -func (rt *router) AppFunc() HandlerFunc { - return func(writer ResponseWriter, request *Request) { - - // find the route - route, params, pathMatched := rt.findRouteFromURL(request.Method, request.URL) - if route == nil { - - if pathMatched { - // no route found, but path was matched: 405 Method Not Allowed - Error(writer, "Method not allowed", http.StatusMethodNotAllowed) - return - } - - // no route found, the path was not matched: 404 Not Found - NotFound(writer, request) - return - } - - // a route was found, set the PathParams - request.PathParams = params - - // run the user code - handler := route.Func - handler(writer, request) - } -} - -// This is run for each new request, perf is important. -func escapedPath(urlObj *url.URL) string { - // the escape method of url.URL should be public - // that would avoid this split. - parts := strings.SplitN(urlObj.RequestURI(), "?", 2) - return parts[0] -} - -var preEscape = strings.NewReplacer("*", "__SPLAT_PLACEHOLDER__", "#", "__RELAXED_PLACEHOLDER__") - -var postEscape = strings.NewReplacer("__SPLAT_PLACEHOLDER__", "*", "__RELAXED_PLACEHOLDER__", "#") - -// This is run at init time only. -func escapedPathExp(pathExp string) (string, error) { - - // PathExp validation - if pathExp == "" { - return "", errors.New("empty PathExp") - } - if pathExp[0] != '/' { - return "", errors.New("PathExp must start with /") - } - if strings.Contains(pathExp, "?") { - return "", errors.New("PathExp must not contain the query string") - } - - // Get the right escaping - // XXX a bit hacky - - pathExp = preEscape.Replace(pathExp) - - urlObj, err := url.Parse(pathExp) - if err != nil { - return "", err - } - - // get the same escaping as find requests - pathExp = urlObj.RequestURI() - - pathExp = postEscape.Replace(pathExp) - - return pathExp, nil -} - -// This validates the Routes and prepares the Trie data structure. -// It must be called once the Routes are defined and before trying to find Routes. -// The order matters, if multiple Routes match, the first defined will be used. -func (rt *router) start() error { - - rt.trie = trie.New() - rt.index = map[*Route]int{} - - for i, route := range rt.Routes { - - // work with the PathExp urlencoded. - pathExp, err := escapedPathExp(route.PathExp) - if err != nil { - return err - } - - // insert in the Trie - err = rt.trie.AddRoute( - strings.ToUpper(route.HttpMethod), // work with the HttpMethod in uppercase - pathExp, - route, - ) - if err != nil { - return err - } - - // index - rt.index[route] = i - } - - if rt.disableTrieCompression == false { - rt.trie.Compress() - } - - return nil -} - -// return the result that has the route defined the earliest -func (rt *router) ofFirstDefinedRoute(matches []*trie.Match) *trie.Match { - minIndex := -1 - var bestMatch *trie.Match - - for _, result := range matches { - route := result.Route.(*Route) - routeIndex := rt.index[route] - if minIndex == -1 || routeIndex < minIndex { - minIndex = routeIndex - bestMatch = result - } - } - - return bestMatch -} - -// Return the first matching Route and the corresponding parameters for a given URL object. -func (rt *router) findRouteFromURL(httpMethod string, urlObj *url.URL) (*Route, map[string]string, bool) { - - // lookup the routes in the Trie - matches, pathMatched := rt.trie.FindRoutesAndPathMatched( - strings.ToUpper(httpMethod), // work with the httpMethod in uppercase - escapedPath(urlObj), // work with the path urlencoded - ) - - // short cuts - if len(matches) == 0 { - // no route found - return nil, nil, pathMatched - } - - if len(matches) == 1 { - // one route found - return matches[0].Route.(*Route), matches[0].Params, pathMatched - } - - // multiple routes found, pick the first defined - result := rt.ofFirstDefinedRoute(matches) - return result.Route.(*Route), result.Params, pathMatched -} - -// Parse the url string (complete or just the path) and return the first matching Route and the corresponding parameters. -func (rt *router) findRoute(httpMethod, urlStr string) (*Route, map[string]string, bool, error) { - - // parse the url - urlObj, err := url.Parse(urlStr) - if err != nil { - return nil, nil, false, err - } - - route, params, pathMatched := rt.findRouteFromURL(httpMethod, urlObj) - return route, params, pathMatched, nil -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/status.go b/vendor/github.com/ant0ine/go-json-rest/rest/status.go deleted file mode 100644 index 6b6b5d1..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/status.go +++ /dev/null @@ -1,129 +0,0 @@ -package rest - -import ( - "fmt" - "log" - "os" - "sync" - "time" -) - -// StatusMiddleware keeps track of various stats about the processed requests. -// It depends on request.Env["STATUS_CODE"] and request.Env["ELAPSED_TIME"], -// recorderMiddleware and timerMiddleware must be in the wrapped middlewares. -type StatusMiddleware struct { - lock sync.RWMutex - start time.Time - pid int - responseCounts map[string]int - totalResponseTime time.Time -} - -// MiddlewareFunc makes StatusMiddleware implement the Middleware interface. -func (mw *StatusMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - - mw.start = time.Now() - mw.pid = os.Getpid() - mw.responseCounts = map[string]int{} - mw.totalResponseTime = time.Time{} - - return func(w ResponseWriter, r *Request) { - - // call the handler - h(w, r) - - if r.Env["STATUS_CODE"] == nil { - log.Fatal("StatusMiddleware: Env[\"STATUS_CODE\"] is nil, " + - "RecorderMiddleware may not be in the wrapped Middlewares.") - } - statusCode := r.Env["STATUS_CODE"].(int) - - if r.Env["ELAPSED_TIME"] == nil { - log.Fatal("StatusMiddleware: Env[\"ELAPSED_TIME\"] is nil, " + - "TimerMiddleware may not be in the wrapped Middlewares.") - } - responseTime := r.Env["ELAPSED_TIME"].(*time.Duration) - - mw.lock.Lock() - mw.responseCounts[fmt.Sprintf("%d", statusCode)]++ - mw.totalResponseTime = mw.totalResponseTime.Add(*responseTime) - mw.lock.Unlock() - } -} - -// Status contains stats and status information. It is returned by GetStatus. -// These information can be made available as an API endpoint, see the "status" -// example to install the following status route. -// GET /.status returns something like: -// -// { -// "Pid": 21732, -// "UpTime": "1m15.926272s", -// "UpTimeSec": 75.926272, -// "Time": "2013-03-04 08:00:27.152986 +0000 UTC", -// "TimeUnix": 1362384027, -// "StatusCodeCount": { -// "200": 53, -// "404": 11 -// }, -// "TotalCount": 64, -// "TotalResponseTime": "16.777ms", -// "TotalResponseTimeSec": 0.016777, -// "AverageResponseTime": "262.14us", -// "AverageResponseTimeSec": 0.00026214 -// } -type Status struct { - Pid int - UpTime string - UpTimeSec float64 - Time string - TimeUnix int64 - StatusCodeCount map[string]int - TotalCount int - TotalResponseTime string - TotalResponseTimeSec float64 - AverageResponseTime string - AverageResponseTimeSec float64 -} - -// GetStatus computes and returns a Status object based on the request informations accumulated -// since the start of the process. -func (mw *StatusMiddleware) GetStatus() *Status { - - mw.lock.RLock() - - now := time.Now() - - uptime := now.Sub(mw.start) - - totalCount := 0 - for _, count := range mw.responseCounts { - totalCount += count - } - - totalResponseTime := mw.totalResponseTime.Sub(time.Time{}) - - averageResponseTime := time.Duration(0) - if totalCount > 0 { - avgNs := int64(totalResponseTime) / int64(totalCount) - averageResponseTime = time.Duration(avgNs) - } - - status := &Status{ - Pid: mw.pid, - UpTime: uptime.String(), - UpTimeSec: uptime.Seconds(), - Time: now.String(), - TimeUnix: now.Unix(), - StatusCodeCount: mw.responseCounts, - TotalCount: totalCount, - TotalResponseTime: totalResponseTime.String(), - TotalResponseTimeSec: totalResponseTime.Seconds(), - AverageResponseTime: averageResponseTime.String(), - AverageResponseTimeSec: averageResponseTime.Seconds(), - } - - mw.lock.RUnlock() - - return status -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/timer.go b/vendor/github.com/ant0ine/go-json-rest/rest/timer.go deleted file mode 100644 index b2616c8..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/timer.go +++ /dev/null @@ -1,26 +0,0 @@ -package rest - -import ( - "time" -) - -// TimerMiddleware computes the elapsed time spent during the execution of the wrapped handler. -// The result is available to the wrapping handlers as request.Env["ELAPSED_TIME"].(*time.Duration), -// and as request.Env["START_TIME"].(*time.Time) -type TimerMiddleware struct{} - -// MiddlewareFunc makes TimerMiddleware implement the Middleware interface. -func (mw *TimerMiddleware) MiddlewareFunc(h HandlerFunc) HandlerFunc { - return func(w ResponseWriter, r *Request) { - - start := time.Now() - r.Env["START_TIME"] = &start - - // call the handler - h(w, r) - - end := time.Now() - elapsed := end.Sub(start) - r.Env["ELAPSED_TIME"] = &elapsed - } -} diff --git a/vendor/github.com/ant0ine/go-json-rest/rest/trie/impl.go b/vendor/github.com/ant0ine/go-json-rest/rest/trie/impl.go deleted file mode 100644 index 2a9fff1..0000000 --- a/vendor/github.com/ant0ine/go-json-rest/rest/trie/impl.go +++ /dev/null @@ -1,426 +0,0 @@ -// Special Trie implementation for HTTP routing. -// -// This Trie implementation is designed to support strings that includes -// :param and *splat parameters. Strings that are commonly used to represent -// the Path in HTTP routing. This implementation also maintain for each Path -// a map of HTTP Methods associated with the Route. -// -// You probably don't need to use this package directly. -// -package trie - -import ( - "errors" - "fmt" -) - -func splitParam(remaining string) (string, string) { - i := 0 - for len(remaining) > i && remaining[i] != '/' && remaining[i] != '.' { - i++ - } - return remaining[:i], remaining[i:] -} - -func splitRelaxed(remaining string) (string, string) { - i := 0 - for len(remaining) > i && remaining[i] != '/' { - i++ - } - return remaining[:i], remaining[i:] -} - -type node struct { - HttpMethodToRoute map[string]interface{} - - Children map[string]*node - ChildrenKeyLen int - - ParamChild *node - ParamName string - - RelaxedChild *node - RelaxedName string - - SplatChild *node - SplatName string -} - -func (n *node) addRoute(httpMethod, pathExp string, route interface{}, usedParams []string) error { - - if len(pathExp) == 0 { - // end of the path, leaf node, update the map - if n.HttpMethodToRoute == nil { - n.HttpMethodToRoute = map[string]interface{}{ - httpMethod: route, - } - return nil - } else { - if n.HttpMethodToRoute[httpMethod] != nil { - return errors.New("node.Route already set, duplicated path and method") - } - n.HttpMethodToRoute[httpMethod] = route - return nil - } - } - - token := pathExp[0:1] - remaining := pathExp[1:] - var nextNode *node - - if token[0] == ':' { - // :param case - var name string - name, remaining = splitParam(remaining) - - // Check param name is unique - for _, e := range usedParams { - if e == name { - return errors.New( - fmt.Sprintf("A route can't have two placeholders with the same name: %s", name), - ) - } - } - usedParams = append(usedParams, name) - - if n.ParamChild == nil { - n.ParamChild = &node{} - n.ParamName = name - } else { - if n.ParamName != name { - return errors.New( - fmt.Sprintf( - "Routes sharing a common placeholder MUST name it consistently: %s != %s", - n.ParamName, - name, - ), - ) - } - } - nextNode = n.ParamChild - } else if token[0] == '#' { - // #param case - var name string - name, remaining = splitRelaxed(remaining) - - // Check param name is unique - for _, e := range usedParams { - if e == name { - return errors.New( - fmt.Sprintf("A route can't have two placeholders with the same name: %s", name), - ) - } - } - usedParams = append(usedParams, name) - - if n.RelaxedChild == nil { - n.RelaxedChild = &node{} - n.RelaxedName = name - } else { - if n.RelaxedName != name { - return errors.New( - fmt.Sprintf( - "Routes sharing a common placeholder MUST name it consistently: %s != %s", - n.RelaxedName, - name, - ), - ) - } - } - nextNode = n.RelaxedChild - } else if token[0] == '*' { - // *splat case - name := remaining - remaining = "" - - // Check param name is unique - for _, e := range usedParams { - if e == name { - return errors.New( - fmt.Sprintf("A route can't have two placeholders with the same name: %s", name), - ) - } - } - - if n.SplatChild == nil { - n.SplatChild = &node{} - n.SplatName = name - } - nextNode = n.SplatChild - } else { - // general case - if n.Children == nil { - n.Children = map[string]*node{} - n.ChildrenKeyLen = 1 - } - if n.Children[token] == nil { - n.Children[token] = &node{} - } - nextNode = n.Children[token] - } - - return nextNode.addRoute(httpMethod, remaining, route, usedParams) -} - -func (n *node) compress() { - // *splat branch - if n.SplatChild != nil { - n.SplatChild.compress() - } - // :param branch - if n.ParamChild != nil { - n.ParamChild.compress() - } - // #param branch - if n.RelaxedChild != nil { - n.RelaxedChild.compress() - } - // main branch - if len(n.Children) == 0 { - return - } - // compressable ? - canCompress := true - for _, node := range n.Children { - if node.HttpMethodToRoute != nil || node.SplatChild != nil || node.ParamChild != nil || node.RelaxedChild != nil { - canCompress = false - } - } - // compress - if canCompress { - merged := map[string]*node{} - for key, node := range n.Children { - for gdKey, gdNode := range node.Children { - mergedKey := key + gdKey - merged[mergedKey] = gdNode - } - } - n.Children = merged - n.ChildrenKeyLen++ - n.compress() - // continue - } else { - for _, node := range n.Children { - node.compress() - } - } -} - -func printFPadding(padding int, format string, a ...interface{}) { - for i := 0; i < padding; i++ { - fmt.Print(" ") - } - fmt.Printf(format, a...) -} - -// Private function for now -func (n *node) printDebug(level int) { - level++ - // *splat branch - if n.SplatChild != nil { - printFPadding(level, "*splat\n") - n.SplatChild.printDebug(level) - } - // :param branch - if n.ParamChild != nil { - printFPadding(level, ":param\n") - n.ParamChild.printDebug(level) - } - // #param branch - if n.RelaxedChild != nil { - printFPadding(level, "#relaxed\n") - n.RelaxedChild.printDebug(level) - } - // main branch - for key, node := range n.Children { - printFPadding(level, "\"%s\"\n", key) - node.printDebug(level) - } -} - -// utility for the node.findRoutes recursive method - -type paramMatch struct { - name string - value string -} - -type findContext struct { - paramStack []paramMatch - matchFunc func(httpMethod, path string, node *node) -} - -func newFindContext() *findContext { - return &findContext{ - paramStack: []paramMatch{}, - } -} - -func (fc *findContext) pushParams(name, value string) { - fc.paramStack = append( - fc.paramStack, - paramMatch{name, value}, - ) -} - -func (fc *findContext) popParams() { - fc.paramStack = fc.paramStack[:len(fc.paramStack)-1] -} - -func (fc *findContext) paramsAsMap() map[string]string { - r := map[string]string{} - for _, param := range fc.paramStack { - if r[param.name] != "" { - // this is checked at addRoute time, and should never happen. - panic(fmt.Sprintf( - "placeholder %s already found, placeholder names should be unique per route", - param.name, - )) - } - r[param.name] = param.value - } - return r -} - -type Match struct { - // Same Route as in AddRoute - Route interface{} - // map of params matched for this result - Params map[string]string -} - -func (n *node) find(httpMethod, path string, context *findContext) { - - if n.HttpMethodToRoute != nil && path == "" { - context.matchFunc(httpMethod, path, n) - } - - if len(path) == 0 { - return - } - - // *splat branch - if n.SplatChild != nil { - context.pushParams(n.SplatName, path) - n.SplatChild.find(httpMethod, "", context) - context.popParams() - } - - // :param branch - if n.ParamChild != nil { - value, remaining := splitParam(path) - context.pushParams(n.ParamName, value) - n.ParamChild.find(httpMethod, remaining, context) - context.popParams() - } - - // #param branch - if n.RelaxedChild != nil { - value, remaining := splitRelaxed(path) - context.pushParams(n.RelaxedName, value) - n.RelaxedChild.find(httpMethod, remaining, context) - context.popParams() - } - - // main branch - length := n.ChildrenKeyLen - if len(path) < length { - return - } - token := path[0:length] - remaining := path[length:] - if n.Children[token] != nil { - n.Children[token].find(httpMethod, remaining, context) - } -} - -type Trie struct { - root *node -} - -// Instanciate a Trie with an empty node as the root. -func New() *Trie { - return &Trie{ - root: &node{}, - } -} - -// Insert the route in the Trie following or creating the nodes corresponding to the path. -func (t *Trie) AddRoute(httpMethod, pathExp string, route interface{}) error { - return t.root.addRoute(httpMethod, pathExp, route, []string{}) -} - -// Reduce the size of the tree, must be done after the last AddRoute. -func (t *Trie) Compress() { - t.root.compress() -} - -// Private function for now. -func (t *Trie) printDebug() { - fmt.Print("\n") - t.root.printDebug(0) - fmt.Print("\n") -} - -// Given a path and an http method, return all the matching routes. -func (t *Trie) FindRoutes(httpMethod, path string) []*Match { - context := newFindContext() - matches := []*Match{} - context.matchFunc = func(httpMethod, path string, node *node) { - if node.HttpMethodToRoute[httpMethod] != nil { - // path and method match, found a route ! - matches = append( - matches, - &Match{ - Route: node.HttpMethodToRoute[httpMethod], - Params: context.paramsAsMap(), - }, - ) - } - } - t.root.find(httpMethod, path, context) - return matches -} - -// Same as FindRoutes, but return in addition a boolean indicating if the path was matched. -// Useful to return 405 -func (t *Trie) FindRoutesAndPathMatched(httpMethod, path string) ([]*Match, bool) { - context := newFindContext() - pathMatched := false - matches := []*Match{} - context.matchFunc = func(httpMethod, path string, node *node) { - pathMatched = true - if node.HttpMethodToRoute[httpMethod] != nil { - // path and method match, found a route ! - matches = append( - matches, - &Match{ - Route: node.HttpMethodToRoute[httpMethod], - Params: context.paramsAsMap(), - }, - ) - } - } - t.root.find(httpMethod, path, context) - return matches, pathMatched -} - -// Given a path, and whatever the http method, return all the matching routes. -func (t *Trie) FindRoutesForPath(path string) []*Match { - context := newFindContext() - matches := []*Match{} - context.matchFunc = func(httpMethod, path string, node *node) { - params := context.paramsAsMap() - for _, route := range node.HttpMethodToRoute { - matches = append( - matches, - &Match{ - Route: route, - Params: params, - }, - ) - } - } - t.root.find("", path, context) - return matches -} diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE deleted file mode 100644 index bc52e96..0000000 --- a/vendor/github.com/davecgh/go-spew/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -ISC License - -Copyright (c) 2012-2016 Dave Collins - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go deleted file mode 100644 index 7929947..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/bypass.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2015-2016 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when the code is not running on Google App Engine, compiled by GopherJS, and -// "-tags safe" is not added to the go build command line. The "disableunsafe" -// tag is deprecated and thus should not be used. -// Go versions prior to 1.4 are disabled because they use a different layout -// for interfaces which make the implementation of unsafeReflectValue more complex. -// +build !js,!appengine,!safe,!disableunsafe,go1.4 - -package spew - -import ( - "reflect" - "unsafe" -) - -const ( - // UnsafeDisabled is a build-time constant which specifies whether or - // not access to the unsafe package is available. - UnsafeDisabled = false - - // ptrSize is the size of a pointer on the current arch. - ptrSize = unsafe.Sizeof((*byte)(nil)) -) - -type flag uintptr - -var ( - // flagRO indicates whether the value field of a reflect.Value - // is read-only. - flagRO flag - - // flagAddr indicates whether the address of the reflect.Value's - // value may be taken. - flagAddr flag -) - -// flagKindMask holds the bits that make up the kind -// part of the flags field. In all the supported versions, -// it is in the lower 5 bits. -const flagKindMask = flag(0x1f) - -// Different versions of Go have used different -// bit layouts for the flags type. This table -// records the known combinations. -var okFlags = []struct { - ro, addr flag -}{{ - // From Go 1.4 to 1.5 - ro: 1 << 5, - addr: 1 << 7, -}, { - // Up to Go tip. - ro: 1<<5 | 1<<6, - addr: 1 << 8, -}} - -var flagValOffset = func() uintptr { - field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") - if !ok { - panic("reflect.Value has no flag field") - } - return field.Offset -}() - -// flagField returns a pointer to the flag field of a reflect.Value. -func flagField(v *reflect.Value) *flag { - return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) -} - -// unsafeReflectValue converts the passed reflect.Value into a one that bypasses -// the typical safety restrictions preventing access to unaddressable and -// unexported data. It works by digging the raw pointer to the underlying -// value out of the protected value and generating a new unprotected (unsafe) -// reflect.Value to it. -// -// This allows us to check for implementations of the Stringer and error -// interfaces to be used for pretty printing ordinarily unaddressable and -// inaccessible values such as unexported struct fields. -func unsafeReflectValue(v reflect.Value) reflect.Value { - if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { - return v - } - flagFieldPtr := flagField(&v) - *flagFieldPtr &^= flagRO - *flagFieldPtr |= flagAddr - return v -} - -// Sanity checks against future reflect package changes -// to the type or semantics of the Value.flag field. -func init() { - field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") - if !ok { - panic("reflect.Value has no flag field") - } - if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { - panic("reflect.Value flag field has changed kind") - } - type t0 int - var t struct { - A t0 - // t0 will have flagEmbedRO set. - t0 - // a will have flagStickyRO set - a t0 - } - vA := reflect.ValueOf(t).FieldByName("A") - va := reflect.ValueOf(t).FieldByName("a") - vt0 := reflect.ValueOf(t).FieldByName("t0") - - // Infer flagRO from the difference between the flags - // for the (otherwise identical) fields in t. - flagPublic := *flagField(&vA) - flagWithRO := *flagField(&va) | *flagField(&vt0) - flagRO = flagPublic ^ flagWithRO - - // Infer flagAddr from the difference between a value - // taken from a pointer and not. - vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") - flagNoPtr := *flagField(&vA) - flagPtr := *flagField(&vPtrA) - flagAddr = flagNoPtr ^ flagPtr - - // Check that the inferred flags tally with one of the known versions. - for _, f := range okFlags { - if flagRO == f.ro && flagAddr == f.addr { - return - } - } - panic("reflect.Value read-only flag has changed semantics") -} diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go deleted file mode 100644 index 205c28d..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015-2016 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when the code is running on Google App Engine, compiled by GopherJS, or -// "-tags safe" is added to the go build command line. The "disableunsafe" -// tag is deprecated and thus should not be used. -// +build js appengine safe disableunsafe !go1.4 - -package spew - -import "reflect" - -const ( - // UnsafeDisabled is a build-time constant which specifies whether or - // not access to the unsafe package is available. - UnsafeDisabled = true -) - -// unsafeReflectValue typically converts the passed reflect.Value into a one -// that bypasses the typical safety restrictions preventing access to -// unaddressable and unexported data. However, doing this relies on access to -// the unsafe package. This is a stub version which simply returns the passed -// reflect.Value when the unsafe package is not available. -func unsafeReflectValue(v reflect.Value) reflect.Value { - return v -} diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go deleted file mode 100644 index 1be8ce9..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/common.go +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "fmt" - "io" - "reflect" - "sort" - "strconv" -) - -// Some constants in the form of bytes to avoid string overhead. This mirrors -// the technique used in the fmt package. -var ( - panicBytes = []byte("(PANIC=") - plusBytes = []byte("+") - iBytes = []byte("i") - trueBytes = []byte("true") - falseBytes = []byte("false") - interfaceBytes = []byte("(interface {})") - commaNewlineBytes = []byte(",\n") - newlineBytes = []byte("\n") - openBraceBytes = []byte("{") - openBraceNewlineBytes = []byte("{\n") - closeBraceBytes = []byte("}") - asteriskBytes = []byte("*") - colonBytes = []byte(":") - colonSpaceBytes = []byte(": ") - openParenBytes = []byte("(") - closeParenBytes = []byte(")") - spaceBytes = []byte(" ") - pointerChainBytes = []byte("->") - nilAngleBytes = []byte("") - maxNewlineBytes = []byte("\n") - maxShortBytes = []byte("") - circularBytes = []byte("") - circularShortBytes = []byte("") - invalidAngleBytes = []byte("") - openBracketBytes = []byte("[") - closeBracketBytes = []byte("]") - percentBytes = []byte("%") - precisionBytes = []byte(".") - openAngleBytes = []byte("<") - closeAngleBytes = []byte(">") - openMapBytes = []byte("map[") - closeMapBytes = []byte("]") - lenEqualsBytes = []byte("len=") - capEqualsBytes = []byte("cap=") -) - -// hexDigits is used to map a decimal value to a hex digit. -var hexDigits = "0123456789abcdef" - -// catchPanic handles any panics that might occur during the handleMethods -// calls. -func catchPanic(w io.Writer, v reflect.Value) { - if err := recover(); err != nil { - w.Write(panicBytes) - fmt.Fprintf(w, "%v", err) - w.Write(closeParenBytes) - } -} - -// handleMethods attempts to call the Error and String methods on the underlying -// type the passed reflect.Value represents and outputes the result to Writer w. -// -// It handles panics in any called methods by catching and displaying the error -// as the formatted value. -func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { - // We need an interface to check if the type implements the error or - // Stringer interface. However, the reflect package won't give us an - // interface on certain things like unexported struct fields in order - // to enforce visibility rules. We use unsafe, when it's available, - // to bypass these restrictions since this package does not mutate the - // values. - if !v.CanInterface() { - if UnsafeDisabled { - return false - } - - v = unsafeReflectValue(v) - } - - // Choose whether or not to do error and Stringer interface lookups against - // the base type or a pointer to the base type depending on settings. - // Technically calling one of these methods with a pointer receiver can - // mutate the value, however, types which choose to satisify an error or - // Stringer interface with a pointer receiver should not be mutating their - // state inside these interface methods. - if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { - v = unsafeReflectValue(v) - } - if v.CanAddr() { - v = v.Addr() - } - - // Is it an error or Stringer? - switch iface := v.Interface().(type) { - case error: - defer catchPanic(w, v) - if cs.ContinueOnMethod { - w.Write(openParenBytes) - w.Write([]byte(iface.Error())) - w.Write(closeParenBytes) - w.Write(spaceBytes) - return false - } - - w.Write([]byte(iface.Error())) - return true - - case fmt.Stringer: - defer catchPanic(w, v) - if cs.ContinueOnMethod { - w.Write(openParenBytes) - w.Write([]byte(iface.String())) - w.Write(closeParenBytes) - w.Write(spaceBytes) - return false - } - w.Write([]byte(iface.String())) - return true - } - return false -} - -// printBool outputs a boolean value as true or false to Writer w. -func printBool(w io.Writer, val bool) { - if val { - w.Write(trueBytes) - } else { - w.Write(falseBytes) - } -} - -// printInt outputs a signed integer value to Writer w. -func printInt(w io.Writer, val int64, base int) { - w.Write([]byte(strconv.FormatInt(val, base))) -} - -// printUint outputs an unsigned integer value to Writer w. -func printUint(w io.Writer, val uint64, base int) { - w.Write([]byte(strconv.FormatUint(val, base))) -} - -// printFloat outputs a floating point value using the specified precision, -// which is expected to be 32 or 64bit, to Writer w. -func printFloat(w io.Writer, val float64, precision int) { - w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) -} - -// printComplex outputs a complex value using the specified float precision -// for the real and imaginary parts to Writer w. -func printComplex(w io.Writer, c complex128, floatPrecision int) { - r := real(c) - w.Write(openParenBytes) - w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) - i := imag(c) - if i >= 0 { - w.Write(plusBytes) - } - w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) - w.Write(iBytes) - w.Write(closeParenBytes) -} - -// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' -// prefix to Writer w. -func printHexPtr(w io.Writer, p uintptr) { - // Null pointer. - num := uint64(p) - if num == 0 { - w.Write(nilAngleBytes) - return - } - - // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix - buf := make([]byte, 18) - - // It's simpler to construct the hex string right to left. - base := uint64(16) - i := len(buf) - 1 - for num >= base { - buf[i] = hexDigits[num%base] - num /= base - i-- - } - buf[i] = hexDigits[num] - - // Add '0x' prefix. - i-- - buf[i] = 'x' - i-- - buf[i] = '0' - - // Strip unused leading bytes. - buf = buf[i:] - w.Write(buf) -} - -// valuesSorter implements sort.Interface to allow a slice of reflect.Value -// elements to be sorted. -type valuesSorter struct { - values []reflect.Value - strings []string // either nil or same len and values - cs *ConfigState -} - -// newValuesSorter initializes a valuesSorter instance, which holds a set of -// surrogate keys on which the data should be sorted. It uses flags in -// ConfigState to decide if and how to populate those surrogate keys. -func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { - vs := &valuesSorter{values: values, cs: cs} - if canSortSimply(vs.values[0].Kind()) { - return vs - } - if !cs.DisableMethods { - vs.strings = make([]string, len(values)) - for i := range vs.values { - b := bytes.Buffer{} - if !handleMethods(cs, &b, vs.values[i]) { - vs.strings = nil - break - } - vs.strings[i] = b.String() - } - } - if vs.strings == nil && cs.SpewKeys { - vs.strings = make([]string, len(values)) - for i := range vs.values { - vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) - } - } - return vs -} - -// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted -// directly, or whether it should be considered for sorting by surrogate keys -// (if the ConfigState allows it). -func canSortSimply(kind reflect.Kind) bool { - // This switch parallels valueSortLess, except for the default case. - switch kind { - case reflect.Bool: - return true - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return true - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return true - case reflect.Float32, reflect.Float64: - return true - case reflect.String: - return true - case reflect.Uintptr: - return true - case reflect.Array: - return true - } - return false -} - -// Len returns the number of values in the slice. It is part of the -// sort.Interface implementation. -func (s *valuesSorter) Len() int { - return len(s.values) -} - -// Swap swaps the values at the passed indices. It is part of the -// sort.Interface implementation. -func (s *valuesSorter) Swap(i, j int) { - s.values[i], s.values[j] = s.values[j], s.values[i] - if s.strings != nil { - s.strings[i], s.strings[j] = s.strings[j], s.strings[i] - } -} - -// valueSortLess returns whether the first value should sort before the second -// value. It is used by valueSorter.Less as part of the sort.Interface -// implementation. -func valueSortLess(a, b reflect.Value) bool { - switch a.Kind() { - case reflect.Bool: - return !a.Bool() && b.Bool() - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return a.Int() < b.Int() - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return a.Uint() < b.Uint() - case reflect.Float32, reflect.Float64: - return a.Float() < b.Float() - case reflect.String: - return a.String() < b.String() - case reflect.Uintptr: - return a.Uint() < b.Uint() - case reflect.Array: - // Compare the contents of both arrays. - l := a.Len() - for i := 0; i < l; i++ { - av := a.Index(i) - bv := b.Index(i) - if av.Interface() == bv.Interface() { - continue - } - return valueSortLess(av, bv) - } - } - return a.String() < b.String() -} - -// Less returns whether the value at index i should sort before the -// value at index j. It is part of the sort.Interface implementation. -func (s *valuesSorter) Less(i, j int) bool { - if s.strings == nil { - return valueSortLess(s.values[i], s.values[j]) - } - return s.strings[i] < s.strings[j] -} - -// sortValues is a sort function that handles both native types and any type that -// can be converted to error or Stringer. Other inputs are sorted according to -// their Value.String() value to ensure display stability. -func sortValues(values []reflect.Value, cs *ConfigState) { - if len(values) == 0 { - return - } - sort.Sort(newValuesSorter(values, cs)) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go deleted file mode 100644 index 2e3d22f..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/config.go +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "fmt" - "io" - "os" -) - -// ConfigState houses the configuration options used by spew to format and -// display values. There is a global instance, Config, that is used to control -// all top-level Formatter and Dump functionality. Each ConfigState instance -// provides methods equivalent to the top-level functions. -// -// The zero value for ConfigState provides no indentation. You would typically -// want to set it to a space or a tab. -// -// Alternatively, you can use NewDefaultConfig to get a ConfigState instance -// with default settings. See the documentation of NewDefaultConfig for default -// values. -type ConfigState struct { - // Indent specifies the string to use for each indentation level. The - // global config instance that all top-level functions use set this to a - // single space by default. If you would like more indentation, you might - // set this to a tab with "\t" or perhaps two spaces with " ". - Indent string - - // MaxDepth controls the maximum number of levels to descend into nested - // data structures. The default, 0, means there is no limit. - // - // NOTE: Circular data structures are properly detected, so it is not - // necessary to set this value unless you specifically want to limit deeply - // nested data structures. - MaxDepth int - - // DisableMethods specifies whether or not error and Stringer interfaces are - // invoked for types that implement them. - DisableMethods bool - - // DisablePointerMethods specifies whether or not to check for and invoke - // error and Stringer interfaces on types which only accept a pointer - // receiver when the current type is not a pointer. - // - // NOTE: This might be an unsafe action since calling one of these methods - // with a pointer receiver could technically mutate the value, however, - // in practice, types which choose to satisify an error or Stringer - // interface with a pointer receiver should not be mutating their state - // inside these interface methods. As a result, this option relies on - // access to the unsafe package, so it will not have any effect when - // running in environments without access to the unsafe package such as - // Google App Engine or with the "safe" build tag specified. - DisablePointerMethods bool - - // DisablePointerAddresses specifies whether to disable the printing of - // pointer addresses. This is useful when diffing data structures in tests. - DisablePointerAddresses bool - - // DisableCapacities specifies whether to disable the printing of capacities - // for arrays, slices, maps and channels. This is useful when diffing - // data structures in tests. - DisableCapacities bool - - // ContinueOnMethod specifies whether or not recursion should continue once - // a custom error or Stringer interface is invoked. The default, false, - // means it will print the results of invoking the custom error or Stringer - // interface and return immediately instead of continuing to recurse into - // the internals of the data type. - // - // NOTE: This flag does not have any effect if method invocation is disabled - // via the DisableMethods or DisablePointerMethods options. - ContinueOnMethod bool - - // SortKeys specifies map keys should be sorted before being printed. Use - // this to have a more deterministic, diffable output. Note that only - // native types (bool, int, uint, floats, uintptr and string) and types - // that support the error or Stringer interfaces (if methods are - // enabled) are supported, with other types sorted according to the - // reflect.Value.String() output which guarantees display stability. - SortKeys bool - - // SpewKeys specifies that, as a last resort attempt, map keys should - // be spewed to strings and sorted by those strings. This is only - // considered if SortKeys is true. - SpewKeys bool -} - -// Config is the active configuration of the top-level functions. -// The configuration can be changed by modifying the contents of spew.Config. -var Config = ConfigState{Indent: " "} - -// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the formatted string as a value that satisfies error. See NewFormatter -// for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { - return fmt.Errorf(format, c.convertArgs(a)...) -} - -// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprint(w, c.convertArgs(a)...) -} - -// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(w, format, c.convertArgs(a)...) -} - -// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it -// passed with a Formatter interface returned by c.NewFormatter. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprintln(w, c.convertArgs(a)...) -} - -// Print is a wrapper for fmt.Print that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Print(a ...interface{}) (n int, err error) { - return fmt.Print(c.convertArgs(a)...) -} - -// Printf is a wrapper for fmt.Printf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { - return fmt.Printf(format, c.convertArgs(a)...) -} - -// Println is a wrapper for fmt.Println that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Println(a ...interface{}) (n int, err error) { - return fmt.Println(c.convertArgs(a)...) -} - -// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Sprint(a ...interface{}) string { - return fmt.Sprint(c.convertArgs(a)...) -} - -// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were -// passed with a Formatter interface returned by c.NewFormatter. It returns -// the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Sprintf(format string, a ...interface{}) string { - return fmt.Sprintf(format, c.convertArgs(a)...) -} - -// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it -// were passed with a Formatter interface returned by c.NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) -func (c *ConfigState) Sprintln(a ...interface{}) string { - return fmt.Sprintln(c.convertArgs(a)...) -} - -/* -NewFormatter returns a custom formatter that satisfies the fmt.Formatter -interface. As a result, it integrates cleanly with standard fmt package -printing functions. The formatter is useful for inline printing of smaller data -types similar to the standard %v format specifier. - -The custom formatter only responds to the %v (most compact), %+v (adds pointer -addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb -combinations. Any other verbs such as %x and %q will be sent to the the -standard fmt package for formatting. In addition, the custom formatter ignores -the width and precision arguments (however they will still work on the format -specifiers not handled by the custom formatter). - -Typically this function shouldn't be called directly. It is much easier to make -use of the custom formatter by calling one of the convenience functions such as -c.Printf, c.Println, or c.Printf. -*/ -func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { - return newFormatter(c, v) -} - -// Fdump formats and displays the passed arguments to io.Writer w. It formats -// exactly the same as Dump. -func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { - fdump(c, w, a...) -} - -/* -Dump displays the passed parameters to standard out with newlines, customizable -indentation, and additional debug information such as complete types and all -pointer addresses used to indirect to the final value. It provides the -following features over the built-in printing facilities provided by the fmt -package: - - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output - -The configuration options are controlled by modifying the public members -of c. See ConfigState for options documentation. - -See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to -get the formatted result as a string. -*/ -func (c *ConfigState) Dump(a ...interface{}) { - fdump(c, os.Stdout, a...) -} - -// Sdump returns a string with the passed arguments formatted exactly the same -// as Dump. -func (c *ConfigState) Sdump(a ...interface{}) string { - var buf bytes.Buffer - fdump(c, &buf, a...) - return buf.String() -} - -// convertArgs accepts a slice of arguments and returns a slice of the same -// length with each argument converted to a spew Formatter interface using -// the ConfigState associated with s. -func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { - formatters = make([]interface{}, len(args)) - for index, arg := range args { - formatters[index] = newFormatter(c, arg) - } - return formatters -} - -// NewDefaultConfig returns a ConfigState with the following default settings. -// -// Indent: " " -// MaxDepth: 0 -// DisableMethods: false -// DisablePointerMethods: false -// ContinueOnMethod: false -// SortKeys: false -func NewDefaultConfig() *ConfigState { - return &ConfigState{Indent: " "} -} diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go deleted file mode 100644 index aacaac6..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/doc.go +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* -Package spew implements a deep pretty printer for Go data structures to aid in -debugging. - -A quick overview of the additional features spew provides over the built-in -printing facilities for Go data types are as follows: - - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output (only when using - Dump style) - -There are two different approaches spew allows for dumping Go data structures: - - * Dump style which prints with newlines, customizable indentation, - and additional debug information such as types and all pointer addresses - used to indirect to the final value - * A custom Formatter interface that integrates cleanly with the standard fmt - package and replaces %v, %+v, %#v, and %#+v to provide inline printing - similar to the default %v while providing the additional functionality - outlined above and passing unsupported format verbs such as %x and %q - along to fmt - -Quick Start - -This section demonstrates how to quickly get started with spew. See the -sections below for further details on formatting and configuration options. - -To dump a variable with full newlines, indentation, type, and pointer -information use Dump, Fdump, or Sdump: - spew.Dump(myVar1, myVar2, ...) - spew.Fdump(someWriter, myVar1, myVar2, ...) - str := spew.Sdump(myVar1, myVar2, ...) - -Alternatively, if you would prefer to use format strings with a compacted inline -printing style, use the convenience wrappers Printf, Fprintf, etc with -%v (most compact), %+v (adds pointer addresses), %#v (adds types), or -%#+v (adds types and pointer addresses): - spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - -Configuration Options - -Configuration of spew is handled by fields in the ConfigState type. For -convenience, all of the top-level functions use a global state available -via the spew.Config global. - -It is also possible to create a ConfigState instance that provides methods -equivalent to the top-level functions. This allows concurrent configuration -options. See the ConfigState documentation for more details. - -The following configuration options are available: - * Indent - String to use for each indentation level for Dump functions. - It is a single space by default. A popular alternative is "\t". - - * MaxDepth - Maximum number of levels to descend into nested data structures. - There is no limit by default. - - * DisableMethods - Disables invocation of error and Stringer interface methods. - Method invocation is enabled by default. - - * DisablePointerMethods - Disables invocation of error and Stringer interface methods on types - which only accept pointer receivers from non-pointer variables. - Pointer method invocation is enabled by default. - - * DisablePointerAddresses - DisablePointerAddresses specifies whether to disable the printing of - pointer addresses. This is useful when diffing data structures in tests. - - * DisableCapacities - DisableCapacities specifies whether to disable the printing of - capacities for arrays, slices, maps and channels. This is useful when - diffing data structures in tests. - - * ContinueOnMethod - Enables recursion into types after invoking error and Stringer interface - methods. Recursion after method invocation is disabled by default. - - * SortKeys - Specifies map keys should be sorted before being printed. Use - this to have a more deterministic, diffable output. Note that - only native types (bool, int, uint, floats, uintptr and string) - and types which implement error or Stringer interfaces are - supported with other types sorted according to the - reflect.Value.String() output which guarantees display - stability. Natural map order is used by default. - - * SpewKeys - Specifies that, as a last resort attempt, map keys should be - spewed to strings and sorted by those strings. This is only - considered if SortKeys is true. - -Dump Usage - -Simply call spew.Dump with a list of variables you want to dump: - - spew.Dump(myVar1, myVar2, ...) - -You may also call spew.Fdump if you would prefer to output to an arbitrary -io.Writer. For example, to dump to standard error: - - spew.Fdump(os.Stderr, myVar1, myVar2, ...) - -A third option is to call spew.Sdump to get the formatted output as a string: - - str := spew.Sdump(myVar1, myVar2, ...) - -Sample Dump Output - -See the Dump example for details on the setup of the types and variables being -shown here. - - (main.Foo) { - unexportedField: (*main.Bar)(0xf84002e210)({ - flag: (main.Flag) flagTwo, - data: (uintptr) - }), - ExportedField: (map[interface {}]interface {}) (len=1) { - (string) (len=3) "one": (bool) true - } - } - -Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C -command as shown. - ([]uint8) (len=32 cap=32) { - 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | - 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| - 00000020 31 32 |12| - } - -Custom Formatter - -Spew provides a custom formatter that implements the fmt.Formatter interface -so that it integrates cleanly with standard fmt package printing functions. The -formatter is useful for inline printing of smaller data types similar to the -standard %v format specifier. - -The custom formatter only responds to the %v (most compact), %+v (adds pointer -addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb -combinations. Any other verbs such as %x and %q will be sent to the the -standard fmt package for formatting. In addition, the custom formatter ignores -the width and precision arguments (however they will still work on the format -specifiers not handled by the custom formatter). - -Custom Formatter Usage - -The simplest way to make use of the spew custom formatter is to call one of the -convenience functions such as spew.Printf, spew.Println, or spew.Printf. The -functions have syntax you are most likely already familiar with: - - spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - spew.Println(myVar, myVar2) - spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) - spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) - -See the Index for the full list convenience functions. - -Sample Formatter Output - -Double pointer to a uint8: - %v: <**>5 - %+v: <**>(0xf8400420d0->0xf8400420c8)5 - %#v: (**uint8)5 - %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 - -Pointer to circular struct with a uint8 field and a pointer to itself: - %v: <*>{1 <*>} - %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} - %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} - %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} - -See the Printf example for details on the setup of variables being shown -here. - -Errors - -Since it is possible for custom Stringer/error interfaces to panic, spew -detects them and handles them internally by printing the panic information -inline with the output. Since spew is intended to provide deep pretty printing -capabilities on structures, it intentionally does not return any errors. -*/ -package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go deleted file mode 100644 index f78d89f..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/dump.go +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "encoding/hex" - "fmt" - "io" - "os" - "reflect" - "regexp" - "strconv" - "strings" -) - -var ( - // uint8Type is a reflect.Type representing a uint8. It is used to - // convert cgo types to uint8 slices for hexdumping. - uint8Type = reflect.TypeOf(uint8(0)) - - // cCharRE is a regular expression that matches a cgo char. - // It is used to detect character arrays to hexdump them. - cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) - - // cUnsignedCharRE is a regular expression that matches a cgo unsigned - // char. It is used to detect unsigned character arrays to hexdump - // them. - cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) - - // cUint8tCharRE is a regular expression that matches a cgo uint8_t. - // It is used to detect uint8_t arrays to hexdump them. - cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) -) - -// dumpState contains information about the state of a dump operation. -type dumpState struct { - w io.Writer - depth int - pointers map[uintptr]int - ignoreNextType bool - ignoreNextIndent bool - cs *ConfigState -} - -// indent performs indentation according to the depth level and cs.Indent -// option. -func (d *dumpState) indent() { - if d.ignoreNextIndent { - d.ignoreNextIndent = false - return - } - d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) -} - -// unpackValue returns values inside of non-nil interfaces when possible. -// This is useful for data types like structs, arrays, slices, and maps which -// can contain varying types packed inside an interface. -func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Interface && !v.IsNil() { - v = v.Elem() - } - return v -} - -// dumpPtr handles formatting of pointers by indirecting them as necessary. -func (d *dumpState) dumpPtr(v reflect.Value) { - // Remove pointers at or below the current depth from map used to detect - // circular refs. - for k, depth := range d.pointers { - if depth >= d.depth { - delete(d.pointers, k) - } - } - - // Keep list of all dereferenced pointers to show later. - pointerChain := make([]uintptr, 0) - - // Figure out how many levels of indirection there are by dereferencing - // pointers and unpacking interfaces down the chain while detecting circular - // references. - nilFound := false - cycleFound := false - indirects := 0 - ve := v - for ve.Kind() == reflect.Ptr { - if ve.IsNil() { - nilFound = true - break - } - indirects++ - addr := ve.Pointer() - pointerChain = append(pointerChain, addr) - if pd, ok := d.pointers[addr]; ok && pd < d.depth { - cycleFound = true - indirects-- - break - } - d.pointers[addr] = d.depth - - ve = ve.Elem() - if ve.Kind() == reflect.Interface { - if ve.IsNil() { - nilFound = true - break - } - ve = ve.Elem() - } - } - - // Display type information. - d.w.Write(openParenBytes) - d.w.Write(bytes.Repeat(asteriskBytes, indirects)) - d.w.Write([]byte(ve.Type().String())) - d.w.Write(closeParenBytes) - - // Display pointer information. - if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { - d.w.Write(openParenBytes) - for i, addr := range pointerChain { - if i > 0 { - d.w.Write(pointerChainBytes) - } - printHexPtr(d.w, addr) - } - d.w.Write(closeParenBytes) - } - - // Display dereferenced value. - d.w.Write(openParenBytes) - switch { - case nilFound: - d.w.Write(nilAngleBytes) - - case cycleFound: - d.w.Write(circularBytes) - - default: - d.ignoreNextType = true - d.dump(ve) - } - d.w.Write(closeParenBytes) -} - -// dumpSlice handles formatting of arrays and slices. Byte (uint8 under -// reflection) arrays and slices are dumped in hexdump -C fashion. -func (d *dumpState) dumpSlice(v reflect.Value) { - // Determine whether this type should be hex dumped or not. Also, - // for types which should be hexdumped, try to use the underlying data - // first, then fall back to trying to convert them to a uint8 slice. - var buf []uint8 - doConvert := false - doHexDump := false - numEntries := v.Len() - if numEntries > 0 { - vt := v.Index(0).Type() - vts := vt.String() - switch { - // C types that need to be converted. - case cCharRE.MatchString(vts): - fallthrough - case cUnsignedCharRE.MatchString(vts): - fallthrough - case cUint8tCharRE.MatchString(vts): - doConvert = true - - // Try to use existing uint8 slices and fall back to converting - // and copying if that fails. - case vt.Kind() == reflect.Uint8: - // We need an addressable interface to convert the type - // to a byte slice. However, the reflect package won't - // give us an interface on certain things like - // unexported struct fields in order to enforce - // visibility rules. We use unsafe, when available, to - // bypass these restrictions since this package does not - // mutate the values. - vs := v - if !vs.CanInterface() || !vs.CanAddr() { - vs = unsafeReflectValue(vs) - } - if !UnsafeDisabled { - vs = vs.Slice(0, numEntries) - - // Use the existing uint8 slice if it can be - // type asserted. - iface := vs.Interface() - if slice, ok := iface.([]uint8); ok { - buf = slice - doHexDump = true - break - } - } - - // The underlying data needs to be converted if it can't - // be type asserted to a uint8 slice. - doConvert = true - } - - // Copy and convert the underlying type if needed. - if doConvert && vt.ConvertibleTo(uint8Type) { - // Convert and copy each element into a uint8 byte - // slice. - buf = make([]uint8, numEntries) - for i := 0; i < numEntries; i++ { - vv := v.Index(i) - buf[i] = uint8(vv.Convert(uint8Type).Uint()) - } - doHexDump = true - } - } - - // Hexdump the entire slice as needed. - if doHexDump { - indent := strings.Repeat(d.cs.Indent, d.depth) - str := indent + hex.Dump(buf) - str = strings.Replace(str, "\n", "\n"+indent, -1) - str = strings.TrimRight(str, d.cs.Indent) - d.w.Write([]byte(str)) - return - } - - // Recursively call dump for each item. - for i := 0; i < numEntries; i++ { - d.dump(d.unpackValue(v.Index(i))) - if i < (numEntries - 1) { - d.w.Write(commaNewlineBytes) - } else { - d.w.Write(newlineBytes) - } - } -} - -// dump is the main workhorse for dumping a value. It uses the passed reflect -// value to figure out what kind of object we are dealing with and formats it -// appropriately. It is a recursive function, however circular data structures -// are detected and handled properly. -func (d *dumpState) dump(v reflect.Value) { - // Handle invalid reflect values immediately. - kind := v.Kind() - if kind == reflect.Invalid { - d.w.Write(invalidAngleBytes) - return - } - - // Handle pointers specially. - if kind == reflect.Ptr { - d.indent() - d.dumpPtr(v) - return - } - - // Print type information unless already handled elsewhere. - if !d.ignoreNextType { - d.indent() - d.w.Write(openParenBytes) - d.w.Write([]byte(v.Type().String())) - d.w.Write(closeParenBytes) - d.w.Write(spaceBytes) - } - d.ignoreNextType = false - - // Display length and capacity if the built-in len and cap functions - // work with the value's kind and the len/cap itself is non-zero. - valueLen, valueCap := 0, 0 - switch v.Kind() { - case reflect.Array, reflect.Slice, reflect.Chan: - valueLen, valueCap = v.Len(), v.Cap() - case reflect.Map, reflect.String: - valueLen = v.Len() - } - if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { - d.w.Write(openParenBytes) - if valueLen != 0 { - d.w.Write(lenEqualsBytes) - printInt(d.w, int64(valueLen), 10) - } - if !d.cs.DisableCapacities && valueCap != 0 { - if valueLen != 0 { - d.w.Write(spaceBytes) - } - d.w.Write(capEqualsBytes) - printInt(d.w, int64(valueCap), 10) - } - d.w.Write(closeParenBytes) - d.w.Write(spaceBytes) - } - - // Call Stringer/error interfaces if they exist and the handle methods flag - // is enabled - if !d.cs.DisableMethods { - if (kind != reflect.Invalid) && (kind != reflect.Interface) { - if handled := handleMethods(d.cs, d.w, v); handled { - return - } - } - } - - switch kind { - case reflect.Invalid: - // Do nothing. We should never get here since invalid has already - // been handled above. - - case reflect.Bool: - printBool(d.w, v.Bool()) - - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - printInt(d.w, v.Int(), 10) - - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - printUint(d.w, v.Uint(), 10) - - case reflect.Float32: - printFloat(d.w, v.Float(), 32) - - case reflect.Float64: - printFloat(d.w, v.Float(), 64) - - case reflect.Complex64: - printComplex(d.w, v.Complex(), 32) - - case reflect.Complex128: - printComplex(d.w, v.Complex(), 64) - - case reflect.Slice: - if v.IsNil() { - d.w.Write(nilAngleBytes) - break - } - fallthrough - - case reflect.Array: - d.w.Write(openBraceNewlineBytes) - d.depth++ - if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { - d.indent() - d.w.Write(maxNewlineBytes) - } else { - d.dumpSlice(v) - } - d.depth-- - d.indent() - d.w.Write(closeBraceBytes) - - case reflect.String: - d.w.Write([]byte(strconv.Quote(v.String()))) - - case reflect.Interface: - // The only time we should get here is for nil interfaces due to - // unpackValue calls. - if v.IsNil() { - d.w.Write(nilAngleBytes) - } - - case reflect.Ptr: - // Do nothing. We should never get here since pointers have already - // been handled above. - - case reflect.Map: - // nil maps should be indicated as different than empty maps - if v.IsNil() { - d.w.Write(nilAngleBytes) - break - } - - d.w.Write(openBraceNewlineBytes) - d.depth++ - if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { - d.indent() - d.w.Write(maxNewlineBytes) - } else { - numEntries := v.Len() - keys := v.MapKeys() - if d.cs.SortKeys { - sortValues(keys, d.cs) - } - for i, key := range keys { - d.dump(d.unpackValue(key)) - d.w.Write(colonSpaceBytes) - d.ignoreNextIndent = true - d.dump(d.unpackValue(v.MapIndex(key))) - if i < (numEntries - 1) { - d.w.Write(commaNewlineBytes) - } else { - d.w.Write(newlineBytes) - } - } - } - d.depth-- - d.indent() - d.w.Write(closeBraceBytes) - - case reflect.Struct: - d.w.Write(openBraceNewlineBytes) - d.depth++ - if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { - d.indent() - d.w.Write(maxNewlineBytes) - } else { - vt := v.Type() - numFields := v.NumField() - for i := 0; i < numFields; i++ { - d.indent() - vtf := vt.Field(i) - d.w.Write([]byte(vtf.Name)) - d.w.Write(colonSpaceBytes) - d.ignoreNextIndent = true - d.dump(d.unpackValue(v.Field(i))) - if i < (numFields - 1) { - d.w.Write(commaNewlineBytes) - } else { - d.w.Write(newlineBytes) - } - } - } - d.depth-- - d.indent() - d.w.Write(closeBraceBytes) - - case reflect.Uintptr: - printHexPtr(d.w, uintptr(v.Uint())) - - case reflect.UnsafePointer, reflect.Chan, reflect.Func: - printHexPtr(d.w, v.Pointer()) - - // There were not any other types at the time this code was written, but - // fall back to letting the default fmt package handle it in case any new - // types are added. - default: - if v.CanInterface() { - fmt.Fprintf(d.w, "%v", v.Interface()) - } else { - fmt.Fprintf(d.w, "%v", v.String()) - } - } -} - -// fdump is a helper function to consolidate the logic from the various public -// methods which take varying writers and config states. -func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { - for _, arg := range a { - if arg == nil { - w.Write(interfaceBytes) - w.Write(spaceBytes) - w.Write(nilAngleBytes) - w.Write(newlineBytes) - continue - } - - d := dumpState{w: w, cs: cs} - d.pointers = make(map[uintptr]int) - d.dump(reflect.ValueOf(arg)) - d.w.Write(newlineBytes) - } -} - -// Fdump formats and displays the passed arguments to io.Writer w. It formats -// exactly the same as Dump. -func Fdump(w io.Writer, a ...interface{}) { - fdump(&Config, w, a...) -} - -// Sdump returns a string with the passed arguments formatted exactly the same -// as Dump. -func Sdump(a ...interface{}) string { - var buf bytes.Buffer - fdump(&Config, &buf, a...) - return buf.String() -} - -/* -Dump displays the passed parameters to standard out with newlines, customizable -indentation, and additional debug information such as complete types and all -pointer addresses used to indirect to the final value. It provides the -following features over the built-in printing facilities provided by the fmt -package: - - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output - -The configuration options are controlled by an exported package global, -spew.Config. See ConfigState for options documentation. - -See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to -get the formatted result as a string. -*/ -func Dump(a ...interface{}) { - fdump(&Config, os.Stdout, a...) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go deleted file mode 100644 index b04edb7..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/format.go +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "bytes" - "fmt" - "reflect" - "strconv" - "strings" -) - -// supportedFlags is a list of all the character flags supported by fmt package. -const supportedFlags = "0-+# " - -// formatState implements the fmt.Formatter interface and contains information -// about the state of a formatting operation. The NewFormatter function can -// be used to get a new Formatter which can be used directly as arguments -// in standard fmt package printing calls. -type formatState struct { - value interface{} - fs fmt.State - depth int - pointers map[uintptr]int - ignoreNextType bool - cs *ConfigState -} - -// buildDefaultFormat recreates the original format string without precision -// and width information to pass in to fmt.Sprintf in the case of an -// unrecognized type. Unless new types are added to the language, this -// function won't ever be called. -func (f *formatState) buildDefaultFormat() (format string) { - buf := bytes.NewBuffer(percentBytes) - - for _, flag := range supportedFlags { - if f.fs.Flag(int(flag)) { - buf.WriteRune(flag) - } - } - - buf.WriteRune('v') - - format = buf.String() - return format -} - -// constructOrigFormat recreates the original format string including precision -// and width information to pass along to the standard fmt package. This allows -// automatic deferral of all format strings this package doesn't support. -func (f *formatState) constructOrigFormat(verb rune) (format string) { - buf := bytes.NewBuffer(percentBytes) - - for _, flag := range supportedFlags { - if f.fs.Flag(int(flag)) { - buf.WriteRune(flag) - } - } - - if width, ok := f.fs.Width(); ok { - buf.WriteString(strconv.Itoa(width)) - } - - if precision, ok := f.fs.Precision(); ok { - buf.Write(precisionBytes) - buf.WriteString(strconv.Itoa(precision)) - } - - buf.WriteRune(verb) - - format = buf.String() - return format -} - -// unpackValue returns values inside of non-nil interfaces when possible and -// ensures that types for values which have been unpacked from an interface -// are displayed when the show types flag is also set. -// This is useful for data types like structs, arrays, slices, and maps which -// can contain varying types packed inside an interface. -func (f *formatState) unpackValue(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Interface { - f.ignoreNextType = false - if !v.IsNil() { - v = v.Elem() - } - } - return v -} - -// formatPtr handles formatting of pointers by indirecting them as necessary. -func (f *formatState) formatPtr(v reflect.Value) { - // Display nil if top level pointer is nil. - showTypes := f.fs.Flag('#') - if v.IsNil() && (!showTypes || f.ignoreNextType) { - f.fs.Write(nilAngleBytes) - return - } - - // Remove pointers at or below the current depth from map used to detect - // circular refs. - for k, depth := range f.pointers { - if depth >= f.depth { - delete(f.pointers, k) - } - } - - // Keep list of all dereferenced pointers to possibly show later. - pointerChain := make([]uintptr, 0) - - // Figure out how many levels of indirection there are by derferencing - // pointers and unpacking interfaces down the chain while detecting circular - // references. - nilFound := false - cycleFound := false - indirects := 0 - ve := v - for ve.Kind() == reflect.Ptr { - if ve.IsNil() { - nilFound = true - break - } - indirects++ - addr := ve.Pointer() - pointerChain = append(pointerChain, addr) - if pd, ok := f.pointers[addr]; ok && pd < f.depth { - cycleFound = true - indirects-- - break - } - f.pointers[addr] = f.depth - - ve = ve.Elem() - if ve.Kind() == reflect.Interface { - if ve.IsNil() { - nilFound = true - break - } - ve = ve.Elem() - } - } - - // Display type or indirection level depending on flags. - if showTypes && !f.ignoreNextType { - f.fs.Write(openParenBytes) - f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) - f.fs.Write([]byte(ve.Type().String())) - f.fs.Write(closeParenBytes) - } else { - if nilFound || cycleFound { - indirects += strings.Count(ve.Type().String(), "*") - } - f.fs.Write(openAngleBytes) - f.fs.Write([]byte(strings.Repeat("*", indirects))) - f.fs.Write(closeAngleBytes) - } - - // Display pointer information depending on flags. - if f.fs.Flag('+') && (len(pointerChain) > 0) { - f.fs.Write(openParenBytes) - for i, addr := range pointerChain { - if i > 0 { - f.fs.Write(pointerChainBytes) - } - printHexPtr(f.fs, addr) - } - f.fs.Write(closeParenBytes) - } - - // Display dereferenced value. - switch { - case nilFound: - f.fs.Write(nilAngleBytes) - - case cycleFound: - f.fs.Write(circularShortBytes) - - default: - f.ignoreNextType = true - f.format(ve) - } -} - -// format is the main workhorse for providing the Formatter interface. It -// uses the passed reflect value to figure out what kind of object we are -// dealing with and formats it appropriately. It is a recursive function, -// however circular data structures are detected and handled properly. -func (f *formatState) format(v reflect.Value) { - // Handle invalid reflect values immediately. - kind := v.Kind() - if kind == reflect.Invalid { - f.fs.Write(invalidAngleBytes) - return - } - - // Handle pointers specially. - if kind == reflect.Ptr { - f.formatPtr(v) - return - } - - // Print type information unless already handled elsewhere. - if !f.ignoreNextType && f.fs.Flag('#') { - f.fs.Write(openParenBytes) - f.fs.Write([]byte(v.Type().String())) - f.fs.Write(closeParenBytes) - } - f.ignoreNextType = false - - // Call Stringer/error interfaces if they exist and the handle methods - // flag is enabled. - if !f.cs.DisableMethods { - if (kind != reflect.Invalid) && (kind != reflect.Interface) { - if handled := handleMethods(f.cs, f.fs, v); handled { - return - } - } - } - - switch kind { - case reflect.Invalid: - // Do nothing. We should never get here since invalid has already - // been handled above. - - case reflect.Bool: - printBool(f.fs, v.Bool()) - - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - printInt(f.fs, v.Int(), 10) - - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - printUint(f.fs, v.Uint(), 10) - - case reflect.Float32: - printFloat(f.fs, v.Float(), 32) - - case reflect.Float64: - printFloat(f.fs, v.Float(), 64) - - case reflect.Complex64: - printComplex(f.fs, v.Complex(), 32) - - case reflect.Complex128: - printComplex(f.fs, v.Complex(), 64) - - case reflect.Slice: - if v.IsNil() { - f.fs.Write(nilAngleBytes) - break - } - fallthrough - - case reflect.Array: - f.fs.Write(openBracketBytes) - f.depth++ - if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { - f.fs.Write(maxShortBytes) - } else { - numEntries := v.Len() - for i := 0; i < numEntries; i++ { - if i > 0 { - f.fs.Write(spaceBytes) - } - f.ignoreNextType = true - f.format(f.unpackValue(v.Index(i))) - } - } - f.depth-- - f.fs.Write(closeBracketBytes) - - case reflect.String: - f.fs.Write([]byte(v.String())) - - case reflect.Interface: - // The only time we should get here is for nil interfaces due to - // unpackValue calls. - if v.IsNil() { - f.fs.Write(nilAngleBytes) - } - - case reflect.Ptr: - // Do nothing. We should never get here since pointers have already - // been handled above. - - case reflect.Map: - // nil maps should be indicated as different than empty maps - if v.IsNil() { - f.fs.Write(nilAngleBytes) - break - } - - f.fs.Write(openMapBytes) - f.depth++ - if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { - f.fs.Write(maxShortBytes) - } else { - keys := v.MapKeys() - if f.cs.SortKeys { - sortValues(keys, f.cs) - } - for i, key := range keys { - if i > 0 { - f.fs.Write(spaceBytes) - } - f.ignoreNextType = true - f.format(f.unpackValue(key)) - f.fs.Write(colonBytes) - f.ignoreNextType = true - f.format(f.unpackValue(v.MapIndex(key))) - } - } - f.depth-- - f.fs.Write(closeMapBytes) - - case reflect.Struct: - numFields := v.NumField() - f.fs.Write(openBraceBytes) - f.depth++ - if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { - f.fs.Write(maxShortBytes) - } else { - vt := v.Type() - for i := 0; i < numFields; i++ { - if i > 0 { - f.fs.Write(spaceBytes) - } - vtf := vt.Field(i) - if f.fs.Flag('+') || f.fs.Flag('#') { - f.fs.Write([]byte(vtf.Name)) - f.fs.Write(colonBytes) - } - f.format(f.unpackValue(v.Field(i))) - } - } - f.depth-- - f.fs.Write(closeBraceBytes) - - case reflect.Uintptr: - printHexPtr(f.fs, uintptr(v.Uint())) - - case reflect.UnsafePointer, reflect.Chan, reflect.Func: - printHexPtr(f.fs, v.Pointer()) - - // There were not any other types at the time this code was written, but - // fall back to letting the default fmt package handle it if any get added. - default: - format := f.buildDefaultFormat() - if v.CanInterface() { - fmt.Fprintf(f.fs, format, v.Interface()) - } else { - fmt.Fprintf(f.fs, format, v.String()) - } - } -} - -// Format satisfies the fmt.Formatter interface. See NewFormatter for usage -// details. -func (f *formatState) Format(fs fmt.State, verb rune) { - f.fs = fs - - // Use standard formatting for verbs that are not v. - if verb != 'v' { - format := f.constructOrigFormat(verb) - fmt.Fprintf(fs, format, f.value) - return - } - - if f.value == nil { - if fs.Flag('#') { - fs.Write(interfaceBytes) - } - fs.Write(nilAngleBytes) - return - } - - f.format(reflect.ValueOf(f.value)) -} - -// newFormatter is a helper function to consolidate the logic from the various -// public methods which take varying config states. -func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { - fs := &formatState{value: v, cs: cs} - fs.pointers = make(map[uintptr]int) - return fs -} - -/* -NewFormatter returns a custom formatter that satisfies the fmt.Formatter -interface. As a result, it integrates cleanly with standard fmt package -printing functions. The formatter is useful for inline printing of smaller data -types similar to the standard %v format specifier. - -The custom formatter only responds to the %v (most compact), %+v (adds pointer -addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb -combinations. Any other verbs such as %x and %q will be sent to the the -standard fmt package for formatting. In addition, the custom formatter ignores -the width and precision arguments (however they will still work on the format -specifiers not handled by the custom formatter). - -Typically this function shouldn't be called directly. It is much easier to make -use of the custom formatter by calling one of the convenience functions such as -Printf, Println, or Fprintf. -*/ -func NewFormatter(v interface{}) fmt.Formatter { - return newFormatter(&Config, v) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go deleted file mode 100644 index 32c0e33..0000000 --- a/vendor/github.com/davecgh/go-spew/spew/spew.go +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew - -import ( - "fmt" - "io" -) - -// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the formatted string as a value that satisfies error. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Errorf(format string, a ...interface{}) (err error) { - return fmt.Errorf(format, convertArgs(a)...) -} - -// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) -func Fprint(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprint(w, convertArgs(a)...) -} - -// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(w, format, convertArgs(a)...) -} - -// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it -// passed with a default Formatter interface returned by NewFormatter. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) -func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprintln(w, convertArgs(a)...) -} - -// Print is a wrapper for fmt.Print that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) -func Print(a ...interface{}) (n int, err error) { - return fmt.Print(convertArgs(a)...) -} - -// Printf is a wrapper for fmt.Printf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Printf(format string, a ...interface{}) (n int, err error) { - return fmt.Printf(format, convertArgs(a)...) -} - -// Println is a wrapper for fmt.Println that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the number of bytes written and any write error encountered. See -// NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) -func Println(a ...interface{}) (n int, err error) { - return fmt.Println(convertArgs(a)...) -} - -// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) -func Sprint(a ...interface{}) string { - return fmt.Sprint(convertArgs(a)...) -} - -// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were -// passed with a default Formatter interface returned by NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) -func Sprintf(format string, a ...interface{}) string { - return fmt.Sprintf(format, convertArgs(a)...) -} - -// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it -// were passed with a default Formatter interface returned by NewFormatter. It -// returns the resulting string. See NewFormatter for formatting details. -// -// This function is shorthand for the following syntax: -// -// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) -func Sprintln(a ...interface{}) string { - return fmt.Sprintln(convertArgs(a)...) -} - -// convertArgs accepts a slice of arguments and returns a slice of the same -// length with each argument converted to a default spew Formatter interface. -func convertArgs(args []interface{}) (formatters []interface{}) { - formatters = make([]interface{}, len(args)) - for index, arg := range args { - formatters[index] = NewFormatter(arg) - } - return formatters -} diff --git a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml b/vendor/github.com/fsnotify/fsnotify/.cirrus.yml deleted file mode 100644 index f4e7dbf..0000000 --- a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml +++ /dev/null @@ -1,14 +0,0 @@ -freebsd_task: - name: 'FreeBSD' - freebsd_instance: - image_family: freebsd-14-1 - install_script: - - pkg update -f - - pkg install -y go - test_script: - # run tests as user "cirrus" instead of root - - pw useradd cirrus -m - - chown -R cirrus:cirrus . - - FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./... - - sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./... - - FSNOTIFY_DEBUG=1 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race -v ./... diff --git a/vendor/github.com/fsnotify/fsnotify/.gitignore b/vendor/github.com/fsnotify/fsnotify/.gitignore deleted file mode 100644 index daea9dd..0000000 --- a/vendor/github.com/fsnotify/fsnotify/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# go test -c output -*.test -*.test.exe - -# Output of go build ./cmd/fsnotify -/fsnotify -/fsnotify.exe - -/test/kqueue -/test/a.out diff --git a/vendor/github.com/fsnotify/fsnotify/.mailmap b/vendor/github.com/fsnotify/fsnotify/.mailmap deleted file mode 100644 index a04f290..0000000 --- a/vendor/github.com/fsnotify/fsnotify/.mailmap +++ /dev/null @@ -1,2 +0,0 @@ -Chris Howey -Nathan Youngman <4566+nathany@users.noreply.github.com> diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md deleted file mode 100644 index fa85478..0000000 --- a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md +++ /dev/null @@ -1,569 +0,0 @@ -# Changelog - -1.8.0 2023-10-31 ----------------- - -### Additions - -- all: add `FSNOTIFY_DEBUG` to print debug logs to stderr ([#619]) - -### Changes and fixes - -- windows: fix behaviour of `WatchList()` to be consistent with other platforms ([#610]) - -- kqueue: ignore events with Ident=0 ([#590]) - -- kqueue: set O_CLOEXEC to prevent passing file descriptors to children ([#617]) - -- kqueue: emit events as "/path/dir/file" instead of "path/link/file" when watching a symlink ([#625]) - -- inotify: don't send event for IN_DELETE_SELF when also watching the parent ([#620]) - -- inotify: fix panic when calling Remove() in a goroutine ([#650]) - -- fen: allow watching subdirectories of watched directories ([#621]) - -[#590]: https://github.com/fsnotify/fsnotify/pull/590 -[#610]: https://github.com/fsnotify/fsnotify/pull/610 -[#617]: https://github.com/fsnotify/fsnotify/pull/617 -[#619]: https://github.com/fsnotify/fsnotify/pull/619 -[#620]: https://github.com/fsnotify/fsnotify/pull/620 -[#621]: https://github.com/fsnotify/fsnotify/pull/621 -[#625]: https://github.com/fsnotify/fsnotify/pull/625 -[#650]: https://github.com/fsnotify/fsnotify/pull/650 - -1.7.0 - 2023-10-22 ------------------- -This version of fsnotify needs Go 1.17. - -### Additions - -- illumos: add FEN backend to support illumos and Solaris. ([#371]) - -- all: add `NewBufferedWatcher()` to use a buffered channel, which can be useful - in cases where you can't control the kernel buffer and receive a large number - of events in bursts. ([#550], [#572]) - -- all: add `AddWith()`, which is identical to `Add()` but allows passing - options. ([#521]) - -- windows: allow setting the ReadDirectoryChangesW() buffer size with - `fsnotify.WithBufferSize()`; the default of 64K is the highest value that - works on all platforms and is enough for most purposes, but in some cases a - highest buffer is needed. ([#521]) - -### Changes and fixes - -- inotify: remove watcher if a watched path is renamed ([#518]) - - After a rename the reported name wasn't updated, or even an empty string. - Inotify doesn't provide any good facilities to update it, so just remove the - watcher. This is already how it worked on kqueue and FEN. - - On Windows this does work, and remains working. - -- windows: don't listen for file attribute changes ([#520]) - - File attribute changes are sent as `FILE_ACTION_MODIFIED` by the Windows API, - with no way to see if they're a file write or attribute change, so would show - up as a fsnotify.Write event. This is never useful, and could result in many - spurious Write events. - -- windows: return `ErrEventOverflow` if the buffer is full ([#525]) - - Before it would merely return "short read", making it hard to detect this - error. - -- kqueue: make sure events for all files are delivered properly when removing a - watched directory ([#526]) - - Previously they would get sent with `""` (empty string) or `"."` as the path - name. - -- kqueue: don't emit spurious Create events for symbolic links ([#524]) - - The link would get resolved but kqueue would "forget" it already saw the link - itself, resulting on a Create for every Write event for the directory. - -- all: return `ErrClosed` on `Add()` when the watcher is closed ([#516]) - -- other: add `Watcher.Errors` and `Watcher.Events` to the no-op `Watcher` in - `backend_other.go`, making it easier to use on unsupported platforms such as - WASM, AIX, etc. ([#528]) - -- other: use the `backend_other.go` no-op if the `appengine` build tag is set; - Google AppEngine forbids usage of the unsafe package so the inotify backend - won't compile there. - -[#371]: https://github.com/fsnotify/fsnotify/pull/371 -[#516]: https://github.com/fsnotify/fsnotify/pull/516 -[#518]: https://github.com/fsnotify/fsnotify/pull/518 -[#520]: https://github.com/fsnotify/fsnotify/pull/520 -[#521]: https://github.com/fsnotify/fsnotify/pull/521 -[#524]: https://github.com/fsnotify/fsnotify/pull/524 -[#525]: https://github.com/fsnotify/fsnotify/pull/525 -[#526]: https://github.com/fsnotify/fsnotify/pull/526 -[#528]: https://github.com/fsnotify/fsnotify/pull/528 -[#537]: https://github.com/fsnotify/fsnotify/pull/537 -[#550]: https://github.com/fsnotify/fsnotify/pull/550 -[#572]: https://github.com/fsnotify/fsnotify/pull/572 - -1.6.0 - 2022-10-13 ------------------- -This version of fsnotify needs Go 1.16 (this was already the case since 1.5.1, -but not documented). It also increases the minimum Linux version to 2.6.32. - -### Additions - -- all: add `Event.Has()` and `Op.Has()` ([#477]) - - This makes checking events a lot easier; for example: - - if event.Op&Write == Write && !(event.Op&Remove == Remove) { - } - - Becomes: - - if event.Has(Write) && !event.Has(Remove) { - } - -- all: add cmd/fsnotify ([#463]) - - A command-line utility for testing and some examples. - -### Changes and fixes - -- inotify: don't ignore events for files that don't exist ([#260], [#470]) - - Previously the inotify watcher would call `os.Lstat()` to check if a file - still exists before emitting events. - - This was inconsistent with other platforms and resulted in inconsistent event - reporting (e.g. when a file is quickly removed and re-created), and generally - a source of confusion. It was added in 2013 to fix a memory leak that no - longer exists. - -- all: return `ErrNonExistentWatch` when `Remove()` is called on a path that's - not watched ([#460]) - -- inotify: replace epoll() with non-blocking inotify ([#434]) - - Non-blocking inotify was not generally available at the time this library was - written in 2014, but now it is. As a result, the minimum Linux version is - bumped from 2.6.27 to 2.6.32. This hugely simplifies the code and is faster. - -- kqueue: don't check for events every 100ms ([#480]) - - The watcher would wake up every 100ms, even when there was nothing to do. Now - it waits until there is something to do. - -- macos: retry opening files on EINTR ([#475]) - -- kqueue: skip unreadable files ([#479]) - - kqueue requires a file descriptor for every file in a directory; this would - fail if a file was unreadable by the current user. Now these files are simply - skipped. - -- windows: fix renaming a watched directory if the parent is also watched ([#370]) - -- windows: increase buffer size from 4K to 64K ([#485]) - -- windows: close file handle on Remove() ([#288]) - -- kqueue: put pathname in the error if watching a file fails ([#471]) - -- inotify, windows: calling Close() more than once could race ([#465]) - -- kqueue: improve Close() performance ([#233]) - -- all: various documentation additions and clarifications. - -[#233]: https://github.com/fsnotify/fsnotify/pull/233 -[#260]: https://github.com/fsnotify/fsnotify/pull/260 -[#288]: https://github.com/fsnotify/fsnotify/pull/288 -[#370]: https://github.com/fsnotify/fsnotify/pull/370 -[#434]: https://github.com/fsnotify/fsnotify/pull/434 -[#460]: https://github.com/fsnotify/fsnotify/pull/460 -[#463]: https://github.com/fsnotify/fsnotify/pull/463 -[#465]: https://github.com/fsnotify/fsnotify/pull/465 -[#470]: https://github.com/fsnotify/fsnotify/pull/470 -[#471]: https://github.com/fsnotify/fsnotify/pull/471 -[#475]: https://github.com/fsnotify/fsnotify/pull/475 -[#477]: https://github.com/fsnotify/fsnotify/pull/477 -[#479]: https://github.com/fsnotify/fsnotify/pull/479 -[#480]: https://github.com/fsnotify/fsnotify/pull/480 -[#485]: https://github.com/fsnotify/fsnotify/pull/485 - -## [1.5.4] - 2022-04-25 - -* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447) -* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444) -* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443) - -## [1.5.3] - 2022-04-22 - -* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445) - -## [1.5.2] - 2022-04-21 - -* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374) -* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361) -* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424) -* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406) -* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416) - -## [1.5.1] - 2021-08-24 - -* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394) - -## [1.5.0] - 2021-08-20 - -* Go: Increase minimum required version to Go 1.12 [#381](https://github.com/fsnotify/fsnotify/pull/381) -* Feature: Add AddRaw method which does not follow symlinks when adding a watch [#289](https://github.com/fsnotify/fsnotify/pull/298) -* Windows: Follow symlinks by default like on all other systems [#289](https://github.com/fsnotify/fsnotify/pull/289) -* CI: Use GitHub Actions for CI and cover go 1.12-1.17 - [#378](https://github.com/fsnotify/fsnotify/pull/378) - [#381](https://github.com/fsnotify/fsnotify/pull/381) - [#385](https://github.com/fsnotify/fsnotify/pull/385) -* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325) - -## [1.4.9] - 2020-03-11 - -* Move example usage to the readme #329. This may resolve #328. - -## [1.4.8] - 2020-03-10 - -* CI: test more go versions (@nathany 1d13583d846ea9d66dcabbfefbfb9d8e6fb05216) -* Tests: Queued inotify events could have been read by the test before max_queued_events was hit (@matthias-stone #265) -* Tests: t.Fatalf -> t.Errorf in go routines (@gdey #266) -* CI: Less verbosity (@nathany #267) -* Tests: Darwin: Exchangedata is deprecated on 10.13 (@nathany #267) -* Tests: Check if channels are closed in the example (@alexeykazakov #244) -* CI: Only run golint on latest version of go and fix issues (@cpuguy83 #284) -* CI: Add windows to travis matrix (@cpuguy83 #284) -* Docs: Remover appveyor badge (@nathany 11844c0959f6fff69ba325d097fce35bd85a8e93) -* Linux: create epoll and pipe fds with close-on-exec (@JohannesEbke #219) -* Linux: open files with close-on-exec (@linxiulei #273) -* Docs: Plan to support fanotify (@nathany ab058b44498e8b7566a799372a39d150d9ea0119 ) -* Project: Add go.mod (@nathany #309) -* Project: Revise editor config (@nathany #309) -* Project: Update copyright for 2019 (@nathany #309) -* CI: Drop go1.8 from CI matrix (@nathany #309) -* Docs: Updating the FAQ section for supportability with NFS & FUSE filesystems (@Pratik32 4bf2d1fec78374803a39307bfb8d340688f4f28e ) - -## [1.4.7] - 2018-01-09 - -* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine) -* Tests: Fix missing verb on format string (thanks @rchiossi) -* Linux: Fix deadlock in Remove (thanks @aarondl) -* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne) -* Docs: Moved FAQ into the README (thanks @vahe) -* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich) -* Docs: replace references to OS X with macOS - -## [1.4.2] - 2016-10-10 - -* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack) - -## [1.4.1] - 2016-10-04 - -* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack) - -## [1.4.0] - 2016-10-01 - -* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie) - -## [1.3.1] - 2016-06-28 - -* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc) - -## [1.3.0] - 2016-04-19 - -* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135) - -## [1.2.10] - 2016-03-02 - -* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj) - -## [1.2.9] - 2016-01-13 - -kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep) - -## [1.2.8] - 2015-12-17 - -* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test) -* inotify: fix race in test -* enable race detection for continuous integration (Linux, Mac, Windows) - -## [1.2.5] - 2015-10-17 - -* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki) -* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken) -* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie) -* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion) - -## [1.2.1] - 2015-10-14 - -* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx) - -## [1.2.0] - 2015-02-08 - -* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD) -* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD) -* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59) - -## [1.1.1] - 2015-02-05 - -* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD) - -## [1.1.0] - 2014-12-12 - -* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43) - * add low-level functions - * only need to store flags on directories - * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13) - * done can be an unbuffered channel - * remove calls to os.NewSyscallError -* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher) -* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48) -* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) - -## [1.0.4] - 2014-09-07 - -* kqueue: add dragonfly to the build tags. -* Rename source code files, rearrange code so exported APIs are at the top. -* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang) - -## [1.0.3] - 2014-08-19 - -* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36) - -## [1.0.2] - 2014-08-17 - -* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) -* [Fix] Make ./path and path equivalent. (thanks @zhsso) - -## [1.0.0] - 2014-08-15 - -* [API] Remove AddWatch on Windows, use Add. -* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30) -* Minor updates based on feedback from golint. - -## dev / 2014-07-09 - -* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify). -* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno) - -## dev / 2014-07-04 - -* kqueue: fix incorrect mutex used in Close() -* Update example to demonstrate usage of Op. - -## dev / 2014-06-28 - -* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4) -* Fix for String() method on Event (thanks Alex Brainman) -* Don't build on Plan 9 or Solaris (thanks @4ad) - -## dev / 2014-06-21 - -* Events channel of type Event rather than *Event. -* [internal] use syscall constants directly for inotify and kqueue. -* [internal] kqueue: rename events to kevents and fileEvent to event. - -## dev / 2014-06-19 - -* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally). -* [internal] remove cookie from Event struct (unused). -* [internal] Event struct has the same definition across every OS. -* [internal] remove internal watch and removeWatch methods. - -## dev / 2014-06-12 - -* [API] Renamed Watch() to Add() and RemoveWatch() to Remove(). -* [API] Pluralized channel names: Events and Errors. -* [API] Renamed FileEvent struct to Event. -* [API] Op constants replace methods like IsCreate(). - -## dev / 2014-06-12 - -* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) - -## dev / 2014-05-23 - -* [API] Remove current implementation of WatchFlags. - * current implementation doesn't take advantage of OS for efficiency - * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes - * no tests for the current implementation - * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195) - -## [0.9.3] - 2014-12-31 - -* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) - -## [0.9.2] - 2014-08-17 - -* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) - -## [0.9.1] - 2014-06-12 - -* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) - -## [0.9.0] - 2014-01-17 - -* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) -* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) -* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. - -## [0.8.12] - 2013-11-13 - -* [API] Remove FD_SET and friends from Linux adapter - -## [0.8.11] - 2013-11-02 - -* [Doc] Add Changelog [#72][] (thanks @nathany) -* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) - -## [0.8.10] - 2013-10-19 - -* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) -* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) -* [Doc] specify OS-specific limits in README (thanks @debrando) - -## [0.8.9] - 2013-09-08 - -* [Doc] Contributing (thanks @nathany) -* [Doc] update package path in example code [#63][] (thanks @paulhammond) -* [Doc] GoCI badge in README (Linux only) [#60][] -* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) - -## [0.8.8] - 2013-06-17 - -* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) - -## [0.8.7] - 2013-06-03 - -* [API] Make syscall flags internal -* [Fix] inotify: ignore event changes -* [Fix] race in symlink test [#45][] (reported by @srid) -* [Fix] tests on Windows -* lower case error messages - -## [0.8.6] - 2013-05-23 - -* kqueue: Use EVT_ONLY flag on Darwin -* [Doc] Update README with full example - -## [0.8.5] - 2013-05-09 - -* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) - -## [0.8.4] - 2013-04-07 - -* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) - -## [0.8.3] - 2013-03-13 - -* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) -* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) - -## [0.8.2] - 2013-02-07 - -* [Doc] add Authors -* [Fix] fix data races for map access [#29][] (thanks @fsouza) - -## [0.8.1] - 2013-01-09 - -* [Fix] Windows path separators -* [Doc] BSD License - -## [0.8.0] - 2012-11-09 - -* kqueue: directory watching improvements (thanks @vmirage) -* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) -* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) - -## [0.7.4] - 2012-10-09 - -* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) -* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) -* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) -* [Fix] kqueue: modify after recreation of file - -## [0.7.3] - 2012-09-27 - -* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) -* [Fix] kqueue: no longer get duplicate CREATE events - -## [0.7.2] - 2012-09-01 - -* kqueue: events for created directories - -## [0.7.1] - 2012-07-14 - -* [Fix] for renaming files - -## [0.7.0] - 2012-07-02 - -* [Feature] FSNotify flags -* [Fix] inotify: Added file name back to event path - -## [0.6.0] - 2012-06-06 - -* kqueue: watch files after directory created (thanks @tmc) - -## [0.5.1] - 2012-05-22 - -* [Fix] inotify: remove all watches before Close() - -## [0.5.0] - 2012-05-03 - -* [API] kqueue: return errors during watch instead of sending over channel -* kqueue: match symlink behavior on Linux -* inotify: add `DELETE_SELF` (requested by @taralx) -* [Fix] kqueue: handle EINTR (reported by @robfig) -* [Doc] Godoc example [#1][] (thanks @davecheney) - -## [0.4.0] - 2012-03-30 - -* Go 1 released: build with go tool -* [Feature] Windows support using winfsnotify -* Windows does not have attribute change notifications -* Roll attribute notifications into IsModify - -## [0.3.0] - 2012-02-19 - -* kqueue: add files when watch directory - -## [0.2.0] - 2011-12-30 - -* update to latest Go weekly code - -## [0.1.0] - 2011-10-19 - -* kqueue: add watch on file creation to match inotify -* kqueue: create file event -* inotify: ignore `IN_IGNORED` events -* event String() -* linux: common FileEvent functions -* initial commit - -[#79]: https://github.com/howeyc/fsnotify/pull/79 -[#77]: https://github.com/howeyc/fsnotify/pull/77 -[#72]: https://github.com/howeyc/fsnotify/issues/72 -[#71]: https://github.com/howeyc/fsnotify/issues/71 -[#70]: https://github.com/howeyc/fsnotify/issues/70 -[#63]: https://github.com/howeyc/fsnotify/issues/63 -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#60]: https://github.com/howeyc/fsnotify/issues/60 -[#59]: https://github.com/howeyc/fsnotify/issues/59 -[#49]: https://github.com/howeyc/fsnotify/issues/49 -[#45]: https://github.com/howeyc/fsnotify/issues/45 -[#40]: https://github.com/howeyc/fsnotify/issues/40 -[#36]: https://github.com/howeyc/fsnotify/issues/36 -[#33]: https://github.com/howeyc/fsnotify/issues/33 -[#29]: https://github.com/howeyc/fsnotify/issues/29 -[#25]: https://github.com/howeyc/fsnotify/issues/25 -[#24]: https://github.com/howeyc/fsnotify/issues/24 -[#21]: https://github.com/howeyc/fsnotify/issues/21 diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md deleted file mode 100644 index e4ac2a2..0000000 --- a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md +++ /dev/null @@ -1,144 +0,0 @@ -Thank you for your interest in contributing to fsnotify! We try to review and -merge PRs in a reasonable timeframe, but please be aware that: - -- To avoid "wasted" work, please discuss changes on the issue tracker first. You - can just send PRs, but they may end up being rejected for one reason or the - other. - -- fsnotify is a cross-platform library, and changes must work reasonably well on - all supported platforms. - -- Changes will need to be compatible; old code should still compile, and the - runtime behaviour can't change in ways that are likely to lead to problems for - users. - -Testing -------- -Just `go test ./...` runs all the tests; the CI runs this on all supported -platforms. Testing different platforms locally can be done with something like -[goon] or [Vagrant], but this isn't super-easy to set up at the moment. - -Use the `-short` flag to make the "stress test" run faster. - -Writing new tests ------------------ -Scripts in the testdata directory allow creating test cases in a "shell-like" -syntax. The basic format is: - - script - - Output: - desired output - -For example: - - # Create a new empty file with some data. - watch / - echo data >/file - - Output: - create /file - write /file - -Just create a new file to add a new test; select which tests to run with -`-run TestScript/[path]`. - -script ------- -The script is a "shell-like" script: - - cmd arg arg - -Comments are supported with `#`: - - # Comment - cmd arg arg # Comment - -All operations are done in a temp directory; a path like "/foo" is rewritten to -"/tmp/TestFoo/foo". - -Arguments can be quoted with `"` or `'`; there are no escapes and they're -functionally identical right now, but this may change in the future, so best to -assume shell-like rules. - - touch "/file with spaces" - -End-of-line escapes with `\` are not supported. - -### Supported commands - - watch path [ops] # Watch the path, reporting events for it. Nothing is - # watched by default. Optionally a list of ops can be - # given, as with AddWith(path, WithOps(...)). - unwatch path # Stop watching the path. - watchlist n # Assert watchlist length. - - stop # Stop running the script; for debugging. - debug [yes/no] # Enable/disable FSNOTIFY_DEBUG (tests are run in - parallel by default, so -parallel=1 is probably a good - idea). - - touch path - mkdir [-p] dir - ln -s target link # Only ln -s supported. - mkfifo path - mknod dev path - mv src dst - rm [-r] path - chmod mode path # Octal only - sleep time-in-ms - - cat path # Read path (does nothing with the data; just reads it). - echo str >>path # Append "str" to "path". - echo str >path # Truncate "path" and write "str". - - require reason # Skip the test if "reason" is true; "skip" and - skip reason # "require" behave identical; it supports both for - # readability. Possible reasons are: - # - # always Always skip this test. - # symlink Symlinks are supported (requires admin - # permissions on Windows). - # mkfifo Platform doesn't support FIFO named sockets. - # mknod Platform doesn't support device nodes. - - -output ------- -After `Output:` the desired output is given; this is indented by convention, but -that's not required. - -The format of that is: - - # Comment - event path # Comment - - system: - event path - system2: - event path - -Every event is one line, and any whitespace between the event and path are -ignored. The path can optionally be surrounded in ". Anything after a "#" is -ignored. - -Platform-specific tests can be added after GOOS; for example: - - watch / - touch /file - - Output: - # Tested if nothing else matches - create /file - - # Windows-specific test. - windows: - write /file - -You can specify multiple platforms with a comma (e.g. "windows, linux:"). -"kqueue" is a shortcut for all kqueue systems (BSD, macOS). - - -[goon]: https://github.com/arp242/goon -[Vagrant]: https://www.vagrantup.com/ -[integration_test.go]: /integration_test.go diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE deleted file mode 100644 index fb03ade..0000000 --- a/vendor/github.com/fsnotify/fsnotify/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright © 2012 The Go Authors. All rights reserved. -Copyright © fsnotify Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. -* Neither the name of Google Inc. nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md deleted file mode 100644 index e480733..0000000 --- a/vendor/github.com/fsnotify/fsnotify/README.md +++ /dev/null @@ -1,184 +0,0 @@ -fsnotify is a Go library to provide cross-platform filesystem notifications on -Windows, Linux, macOS, BSD, and illumos. - -Go 1.17 or newer is required; the full documentation is at -https://pkg.go.dev/github.com/fsnotify/fsnotify - ---- - -Platform support: - -| Backend | OS | Status | -| :-------------------- | :--------- | :------------------------------------------------------------------------ | -| inotify | Linux | Supported | -| kqueue | BSD, macOS | Supported | -| ReadDirectoryChangesW | Windows | Supported | -| FEN | illumos | Supported | -| fanotify | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114) | -| AHAFS | AIX | [aix branch]; experimental due to lack of maintainer and test environment | -| FSEvents | macOS | [Needs support in x/sys/unix][fsevents] | -| USN Journals | Windows | [Needs support in x/sys/windows][usn] | -| Polling | *All* | [Not yet](https://github.com/fsnotify/fsnotify/issues/9) | - -Linux and illumos should include Android and Solaris, but these are currently -untested. - -[fsevents]: https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120 -[usn]: https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847 -[aix branch]: https://github.com/fsnotify/fsnotify/issues/353#issuecomment-1284590129 - -Usage ------ -A basic example: - -```go -package main - -import ( - "log" - - "github.com/fsnotify/fsnotify" -) - -func main() { - // Create new watcher. - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Fatal(err) - } - defer watcher.Close() - - // Start listening for events. - go func() { - for { - select { - case event, ok := <-watcher.Events: - if !ok { - return - } - log.Println("event:", event) - if event.Has(fsnotify.Write) { - log.Println("modified file:", event.Name) - } - case err, ok := <-watcher.Errors: - if !ok { - return - } - log.Println("error:", err) - } - } - }() - - // Add a path. - err = watcher.Add("/tmp") - if err != nil { - log.Fatal(err) - } - - // Block main goroutine forever. - <-make(chan struct{}) -} -``` - -Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be -run with: - - % go run ./cmd/fsnotify - -Further detailed documentation can be found in godoc: -https://pkg.go.dev/github.com/fsnotify/fsnotify - -FAQ ---- -### Will a file still be watched when it's moved to another directory? -No, not unless you are watching the location it was moved to. - -### Are subdirectories watched? -No, you must add watches for any directory you want to watch (a recursive -watcher is on the roadmap: [#18]). - -[#18]: https://github.com/fsnotify/fsnotify/issues/18 - -### Do I have to watch the Error and Event channels in a goroutine? -Yes. You can read both channels in the same goroutine using `select` (you don't -need a separate goroutine for both channels; see the example). - -### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys? -fsnotify requires support from underlying OS to work. The current NFS and SMB -protocols does not provide network level support for file notifications, and -neither do the /proc and /sys virtual filesystems. - -This could be fixed with a polling watcher ([#9]), but it's not yet implemented. - -[#9]: https://github.com/fsnotify/fsnotify/issues/9 - -### Why do I get many Chmod events? -Some programs may generate a lot of attribute changes; for example Spotlight on -macOS, anti-virus programs, backup applications, and some others are known to do -this. As a rule, it's typically best to ignore Chmod events. They're often not -useful, and tend to cause problems. - -Spotlight indexing on macOS can result in multiple events (see [#15]). A -temporary workaround is to add your folder(s) to the *Spotlight Privacy -settings* until we have a native FSEvents implementation (see [#11]). - -[#11]: https://github.com/fsnotify/fsnotify/issues/11 -[#15]: https://github.com/fsnotify/fsnotify/issues/15 - -### Watching a file doesn't work well -Watching individual files (rather than directories) is generally not recommended -as many programs (especially editors) update files atomically: it will write to -a temporary file which is then moved to to destination, overwriting the original -(or some variant thereof). The watcher on the original file is now lost, as that -no longer exists. - -The upshot of this is that a power failure or crash won't leave a half-written -file. - -Watch the parent directory and use `Event.Name` to filter out files you're not -interested in. There is an example of this in `cmd/fsnotify/file.go`. - -Platform-specific notes ------------------------ -### Linux -When a file is removed a REMOVE event won't be emitted until all file -descriptors are closed; it will emit a CHMOD instead: - - fp := os.Open("file") - os.Remove("file") // CHMOD - fp.Close() // REMOVE - -This is the event that inotify sends, so not much can be changed about this. - -The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for -the number of watches per user, and `fs.inotify.max_user_instances` specifies -the maximum number of inotify instances per user. Every Watcher you create is an -"instance", and every path you add is a "watch". - -These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and -`/proc/sys/fs/inotify/max_user_instances` - -To increase them you can use `sysctl` or write the value to proc file: - - # The default values on Linux 5.18 - sysctl fs.inotify.max_user_watches=124983 - sysctl fs.inotify.max_user_instances=128 - -To make the changes persist on reboot edit `/etc/sysctl.conf` or -`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your -distro's documentation): - - fs.inotify.max_user_watches=124983 - fs.inotify.max_user_instances=128 - -Reaching the limit will result in a "no space left on device" or "too many open -files" error. - -### kqueue (macOS, all BSD systems) -kqueue requires opening a file descriptor for every file that's being watched; -so if you're watching a directory with five files then that's six file -descriptors. You will run in to your system's "max open files" limit faster on -these platforms. - -The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to -control the maximum number of open files. diff --git a/vendor/github.com/fsnotify/fsnotify/backend_fen.go b/vendor/github.com/fsnotify/fsnotify/backend_fen.go deleted file mode 100644 index c349c32..0000000 --- a/vendor/github.com/fsnotify/fsnotify/backend_fen.go +++ /dev/null @@ -1,484 +0,0 @@ -//go:build solaris - -// FEN backend for illumos (supported) and Solaris (untested, but should work). -// -// See port_create(3c) etc. for docs. https://www.illumos.org/man/3C/port_create - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "sync" - "time" - - "github.com/fsnotify/fsnotify/internal" - "golang.org/x/sys/unix" -) - -type fen struct { - Events chan Event - Errors chan error - - mu sync.Mutex - port *unix.EventPort - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - dirs map[string]Op // Explicitly watched directories - watches map[string]Op // Explicitly watched non-directories -} - -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(0, ev, errs) -} - -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { - w := &fen{ - Events: ev, - Errors: errs, - dirs: make(map[string]Op), - watches: make(map[string]Op), - done: make(chan struct{}), - } - - var err error - w.port, err = unix.NewEventPort() - if err != nil { - return nil, fmt.Errorf("fsnotify.NewWatcher: %w", err) - } - - go w.readEvents() - return w, nil -} - -// sendEvent attempts to send an event to the user, returning true if the event -// was put in the channel successfully and false if the watcher has been closed. -func (w *fen) sendEvent(name string, op Op) (sent bool) { - select { - case <-w.done: - return false - case w.Events <- Event{Name: name, Op: op}: - return true - } -} - -// sendError attempts to send an error to the user, returning true if the error -// was put in the channel successfully and false if the watcher has been closed. -func (w *fen) sendError(err error) (sent bool) { - if err == nil { - return true - } - select { - case <-w.done: - return false - case w.Errors <- err: - return true - } -} - -func (w *fen) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - -func (w *fen) Close() error { - // Take the lock used by associateFile to prevent lingering events from - // being processed after the close - w.mu.Lock() - defer w.mu.Unlock() - if w.isClosed() { - return nil - } - close(w.done) - return w.port.Close() -} - -func (w *fen) Add(name string) error { return w.AddWith(name) } - -func (w *fen) AddWith(name string, opts ...addOpt) error { - if w.isClosed() { - return ErrClosed - } - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n", - time.Now().Format("15:04:05.000000000"), name) - } - - with := getOptions(opts...) - if !w.xSupports(with.op) { - return fmt.Errorf("%w: %s", xErrUnsupported, with.op) - } - - // Currently we resolve symlinks that were explicitly requested to be - // watched. Otherwise we would use LStat here. - stat, err := os.Stat(name) - if err != nil { - return err - } - - // Associate all files in the directory. - if stat.IsDir() { - err := w.handleDirectory(name, stat, true, w.associateFile) - if err != nil { - return err - } - - w.mu.Lock() - w.dirs[name] = with.op - w.mu.Unlock() - return nil - } - - err = w.associateFile(name, stat, true) - if err != nil { - return err - } - - w.mu.Lock() - w.watches[name] = with.op - w.mu.Unlock() - return nil -} - -func (w *fen) Remove(name string) error { - if w.isClosed() { - return nil - } - if !w.port.PathIsWatched(name) { - return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) - } - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n", - time.Now().Format("15:04:05.000000000"), name) - } - - // The user has expressed an intent. Immediately remove this name from - // whichever watch list it might be in. If it's not in there the delete - // doesn't cause harm. - w.mu.Lock() - delete(w.watches, name) - delete(w.dirs, name) - w.mu.Unlock() - - stat, err := os.Stat(name) - if err != nil { - return err - } - - // Remove associations for every file in the directory. - if stat.IsDir() { - err := w.handleDirectory(name, stat, false, w.dissociateFile) - if err != nil { - return err - } - return nil - } - - err = w.port.DissociatePath(name) - if err != nil { - return err - } - - return nil -} - -// readEvents contains the main loop that runs in a goroutine watching for events. -func (w *fen) readEvents() { - // If this function returns, the watcher has been closed and we can close - // these channels - defer func() { - close(w.Errors) - close(w.Events) - }() - - pevents := make([]unix.PortEvent, 8) - for { - count, err := w.port.Get(pevents, 1, nil) - if err != nil && err != unix.ETIME { - // Interrupted system call (count should be 0) ignore and continue - if errors.Is(err, unix.EINTR) && count == 0 { - continue - } - // Get failed because we called w.Close() - if errors.Is(err, unix.EBADF) && w.isClosed() { - return - } - // There was an error not caused by calling w.Close() - if !w.sendError(err) { - return - } - } - - p := pevents[:count] - for _, pevent := range p { - if pevent.Source != unix.PORT_SOURCE_FILE { - // Event from unexpected source received; should never happen. - if !w.sendError(errors.New("Event from unexpected source received")) { - return - } - continue - } - - if debug { - internal.Debug(pevent.Path, pevent.Events) - } - - err = w.handleEvent(&pevent) - if !w.sendError(err) { - return - } - } - } -} - -func (w *fen) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error { - files, err := os.ReadDir(path) - if err != nil { - return err - } - - // Handle all children of the directory. - for _, entry := range files { - finfo, err := entry.Info() - if err != nil { - return err - } - err = handler(filepath.Join(path, finfo.Name()), finfo, false) - if err != nil { - return err - } - } - - // And finally handle the directory itself. - return handler(path, stat, follow) -} - -// handleEvent might need to emit more than one fsnotify event if the events -// bitmap matches more than one event type (e.g. the file was both modified and -// had the attributes changed between when the association was created and the -// when event was returned) -func (w *fen) handleEvent(event *unix.PortEvent) error { - var ( - events = event.Events - path = event.Path - fmode = event.Cookie.(os.FileMode) - reRegister = true - ) - - w.mu.Lock() - _, watchedDir := w.dirs[path] - _, watchedPath := w.watches[path] - w.mu.Unlock() - isWatched := watchedDir || watchedPath - - if events&unix.FILE_DELETE != 0 { - if !w.sendEvent(path, Remove) { - return nil - } - reRegister = false - } - if events&unix.FILE_RENAME_FROM != 0 { - if !w.sendEvent(path, Rename) { - return nil - } - // Don't keep watching the new file name - reRegister = false - } - if events&unix.FILE_RENAME_TO != 0 { - // We don't report a Rename event for this case, because Rename events - // are interpreted as referring to the _old_ name of the file, and in - // this case the event would refer to the new name of the file. This - // type of rename event is not supported by fsnotify. - - // inotify reports a Remove event in this case, so we simulate this - // here. - if !w.sendEvent(path, Remove) { - return nil - } - // Don't keep watching the file that was removed - reRegister = false - } - - // The file is gone, nothing left to do. - if !reRegister { - if watchedDir { - w.mu.Lock() - delete(w.dirs, path) - w.mu.Unlock() - } - if watchedPath { - w.mu.Lock() - delete(w.watches, path) - w.mu.Unlock() - } - return nil - } - - // If we didn't get a deletion the file still exists and we're going to have - // to watch it again. Let's Stat it now so that we can compare permissions - // and have what we need to continue watching the file - - stat, err := os.Lstat(path) - if err != nil { - // This is unexpected, but we should still emit an event. This happens - // most often on "rm -r" of a subdirectory inside a watched directory We - // get a modify event of something happening inside, but by the time we - // get here, the sudirectory is already gone. Clearly we were watching - // this path but now it is gone. Let's tell the user that it was - // removed. - if !w.sendEvent(path, Remove) { - return nil - } - // Suppress extra write events on removed directories; they are not - // informative and can be confusing. - return nil - } - - // resolve symlinks that were explicitly watched as we would have at Add() - // time. this helps suppress spurious Chmod events on watched symlinks - if isWatched { - stat, err = os.Stat(path) - if err != nil { - // The symlink still exists, but the target is gone. Report the - // Remove similar to above. - if !w.sendEvent(path, Remove) { - return nil - } - // Don't return the error - } - } - - if events&unix.FILE_MODIFIED != 0 { - if fmode.IsDir() && watchedDir { - if err := w.updateDirectory(path); err != nil { - return err - } - } else { - if !w.sendEvent(path, Write) { - return nil - } - } - } - if events&unix.FILE_ATTRIB != 0 && stat != nil { - // Only send Chmod if perms changed - if stat.Mode().Perm() != fmode.Perm() { - if !w.sendEvent(path, Chmod) { - return nil - } - } - } - - if stat != nil { - // If we get here, it means we've hit an event above that requires us to - // continue watching the file or directory - return w.associateFile(path, stat, isWatched) - } - return nil -} - -func (w *fen) updateDirectory(path string) error { - // The directory was modified, so we must find unwatched entities and watch - // them. If something was removed from the directory, nothing will happen, - // as everything else should still be watched. - files, err := os.ReadDir(path) - if err != nil { - return err - } - - for _, entry := range files { - path := filepath.Join(path, entry.Name()) - if w.port.PathIsWatched(path) { - continue - } - - finfo, err := entry.Info() - if err != nil { - return err - } - err = w.associateFile(path, finfo, false) - if !w.sendError(err) { - return nil - } - if !w.sendEvent(path, Create) { - return nil - } - } - return nil -} - -func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error { - if w.isClosed() { - return ErrClosed - } - // This is primarily protecting the call to AssociatePath but it is - // important and intentional that the call to PathIsWatched is also - // protected by this mutex. Without this mutex, AssociatePath has been seen - // to error out that the path is already associated. - w.mu.Lock() - defer w.mu.Unlock() - - if w.port.PathIsWatched(path) { - // Remove the old association in favor of this one If we get ENOENT, - // then while the x/sys/unix wrapper still thought that this path was - // associated, the underlying event port did not. This call will have - // cleared up that discrepancy. The most likely cause is that the event - // has fired but we haven't processed it yet. - err := w.port.DissociatePath(path) - if err != nil && !errors.Is(err, unix.ENOENT) { - return err - } - } - - var events int - if !follow { - // Watch symlinks themselves rather than their targets unless this entry - // is explicitly watched. - events |= unix.FILE_NOFOLLOW - } - if true { // TODO: implement withOps() - events |= unix.FILE_MODIFIED - } - if true { - events |= unix.FILE_ATTRIB - } - return w.port.AssociatePath(path, stat, events, stat.Mode()) -} - -func (w *fen) dissociateFile(path string, stat os.FileInfo, unused bool) error { - if !w.port.PathIsWatched(path) { - return nil - } - return w.port.DissociatePath(path) -} - -func (w *fen) WatchList() []string { - if w.isClosed() { - return nil - } - - w.mu.Lock() - defer w.mu.Unlock() - - entries := make([]string, 0, len(w.watches)+len(w.dirs)) - for pathname := range w.dirs { - entries = append(entries, pathname) - } - for pathname := range w.watches { - entries = append(entries, pathname) - } - - return entries -} - -func (w *fen) xSupports(op Op) bool { - if op.Has(xUnportableOpen) || op.Has(xUnportableRead) || - op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) { - return false - } - return true -} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go deleted file mode 100644 index 36c3116..0000000 --- a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go +++ /dev/null @@ -1,658 +0,0 @@ -//go:build linux && !appengine - -package fsnotify - -import ( - "errors" - "fmt" - "io" - "io/fs" - "os" - "path/filepath" - "strings" - "sync" - "time" - "unsafe" - - "github.com/fsnotify/fsnotify/internal" - "golang.org/x/sys/unix" -) - -type inotify struct { - Events chan Event - Errors chan error - - // Store fd here as os.File.Read() will no longer return on close after - // calling Fd(). See: https://github.com/golang/go/issues/26439 - fd int - inotifyFile *os.File - watches *watches - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - doneMu sync.Mutex - doneResp chan struct{} // Channel to respond to Close - - // Store rename cookies in an array, with the index wrapping to 0. Almost - // all of the time what we get is a MOVED_FROM to set the cookie and the - // next event inotify sends will be MOVED_TO to read it. However, this is - // not guaranteed – as described in inotify(7) – and we may get other events - // between the two MOVED_* events (including other MOVED_* ones). - // - // A second issue is that moving a file outside the watched directory will - // trigger a MOVED_FROM to set the cookie, but we never see the MOVED_TO to - // read and delete it. So just storing it in a map would slowly leak memory. - // - // Doing it like this gives us a simple fast LRU-cache that won't allocate. - // Ten items should be more than enough for our purpose, and a loop over - // such a short array is faster than a map access anyway (not that it hugely - // matters since we're talking about hundreds of ns at the most, but still). - cookies [10]koekje - cookieIndex uint8 - cookiesMu sync.Mutex -} - -type ( - watches struct { - mu sync.RWMutex - wd map[uint32]*watch // wd → watch - path map[string]uint32 // pathname → wd - } - watch struct { - wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) - flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) - path string // Watch path. - recurse bool // Recursion with ./...? - } - koekje struct { - cookie uint32 - path string - } -) - -func newWatches() *watches { - return &watches{ - wd: make(map[uint32]*watch), - path: make(map[string]uint32), - } -} - -func (w *watches) len() int { - w.mu.RLock() - defer w.mu.RUnlock() - return len(w.wd) -} - -func (w *watches) add(ww *watch) { - w.mu.Lock() - defer w.mu.Unlock() - w.wd[ww.wd] = ww - w.path[ww.path] = ww.wd -} - -func (w *watches) remove(wd uint32) { - w.mu.Lock() - defer w.mu.Unlock() - watch := w.wd[wd] // Could have had Remove() called. See #616. - if watch == nil { - return - } - delete(w.path, watch.path) - delete(w.wd, wd) -} - -func (w *watches) removePath(path string) ([]uint32, error) { - w.mu.Lock() - defer w.mu.Unlock() - - path, recurse := recursivePath(path) - wd, ok := w.path[path] - if !ok { - return nil, fmt.Errorf("%w: %s", ErrNonExistentWatch, path) - } - - watch := w.wd[wd] - if recurse && !watch.recurse { - return nil, fmt.Errorf("can't use /... with non-recursive watch %q", path) - } - - delete(w.path, path) - delete(w.wd, wd) - if !watch.recurse { - return []uint32{wd}, nil - } - - wds := make([]uint32, 0, 8) - wds = append(wds, wd) - for p, rwd := range w.path { - if filepath.HasPrefix(p, path) { - delete(w.path, p) - delete(w.wd, rwd) - wds = append(wds, rwd) - } - } - return wds, nil -} - -func (w *watches) byPath(path string) *watch { - w.mu.RLock() - defer w.mu.RUnlock() - return w.wd[w.path[path]] -} - -func (w *watches) byWd(wd uint32) *watch { - w.mu.RLock() - defer w.mu.RUnlock() - return w.wd[wd] -} - -func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error { - w.mu.Lock() - defer w.mu.Unlock() - - var existing *watch - wd, ok := w.path[path] - if ok { - existing = w.wd[wd] - } - - upd, err := f(existing) - if err != nil { - return err - } - if upd != nil { - w.wd[upd.wd] = upd - w.path[upd.path] = upd.wd - - if upd.wd != wd { - delete(w.wd, wd) - } - } - - return nil -} - -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(0, ev, errs) -} - -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { - // Need to set nonblocking mode for SetDeadline to work, otherwise blocking - // I/O operations won't terminate on close. - fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK) - if fd == -1 { - return nil, errno - } - - w := &inotify{ - Events: ev, - Errors: errs, - fd: fd, - inotifyFile: os.NewFile(uintptr(fd), ""), - watches: newWatches(), - done: make(chan struct{}), - doneResp: make(chan struct{}), - } - - go w.readEvents() - return w, nil -} - -// Returns true if the event was sent, or false if watcher is closed. -func (w *inotify) sendEvent(e Event) bool { - select { - case <-w.done: - return false - case w.Events <- e: - return true - } -} - -// Returns true if the error was sent, or false if watcher is closed. -func (w *inotify) sendError(err error) bool { - if err == nil { - return true - } - select { - case <-w.done: - return false - case w.Errors <- err: - return true - } -} - -func (w *inotify) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - -func (w *inotify) Close() error { - w.doneMu.Lock() - if w.isClosed() { - w.doneMu.Unlock() - return nil - } - close(w.done) - w.doneMu.Unlock() - - // Causes any blocking reads to return with an error, provided the file - // still supports deadline operations. - err := w.inotifyFile.Close() - if err != nil { - return err - } - - // Wait for goroutine to close - <-w.doneResp - - return nil -} - -func (w *inotify) Add(name string) error { return w.AddWith(name) } - -func (w *inotify) AddWith(path string, opts ...addOpt) error { - if w.isClosed() { - return ErrClosed - } - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n", - time.Now().Format("15:04:05.000000000"), path) - } - - with := getOptions(opts...) - if !w.xSupports(with.op) { - return fmt.Errorf("%w: %s", xErrUnsupported, with.op) - } - - path, recurse := recursivePath(path) - if recurse { - return filepath.WalkDir(path, func(root string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if !d.IsDir() { - if root == path { - return fmt.Errorf("fsnotify: not a directory: %q", path) - } - return nil - } - - // Send a Create event when adding new directory from a recursive - // watch; this is for "mkdir -p one/two/three". Usually all those - // directories will be created before we can set up watchers on the - // subdirectories, so only "one" would be sent as a Create event and - // not "one/two" and "one/two/three" (inotifywait -r has the same - // problem). - if with.sendCreate && root != path { - w.sendEvent(Event{Name: root, Op: Create}) - } - - return w.add(root, with, true) - }) - } - - return w.add(path, with, false) -} - -func (w *inotify) add(path string, with withOpts, recurse bool) error { - var flags uint32 - if with.noFollow { - flags |= unix.IN_DONT_FOLLOW - } - if with.op.Has(Create) { - flags |= unix.IN_CREATE - } - if with.op.Has(Write) { - flags |= unix.IN_MODIFY - } - if with.op.Has(Remove) { - flags |= unix.IN_DELETE | unix.IN_DELETE_SELF - } - if with.op.Has(Rename) { - flags |= unix.IN_MOVED_TO | unix.IN_MOVED_FROM | unix.IN_MOVE_SELF - } - if with.op.Has(Chmod) { - flags |= unix.IN_ATTRIB - } - if with.op.Has(xUnportableOpen) { - flags |= unix.IN_OPEN - } - if with.op.Has(xUnportableRead) { - flags |= unix.IN_ACCESS - } - if with.op.Has(xUnportableCloseWrite) { - flags |= unix.IN_CLOSE_WRITE - } - if with.op.Has(xUnportableCloseRead) { - flags |= unix.IN_CLOSE_NOWRITE - } - return w.register(path, flags, recurse) -} - -func (w *inotify) register(path string, flags uint32, recurse bool) error { - return w.watches.updatePath(path, func(existing *watch) (*watch, error) { - if existing != nil { - flags |= existing.flags | unix.IN_MASK_ADD - } - - wd, err := unix.InotifyAddWatch(w.fd, path, flags) - if wd == -1 { - return nil, err - } - - if existing == nil { - return &watch{ - wd: uint32(wd), - path: path, - flags: flags, - recurse: recurse, - }, nil - } - - existing.wd = uint32(wd) - existing.flags = flags - return existing, nil - }) -} - -func (w *inotify) Remove(name string) error { - if w.isClosed() { - return nil - } - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n", - time.Now().Format("15:04:05.000000000"), name) - } - return w.remove(filepath.Clean(name)) -} - -func (w *inotify) remove(name string) error { - wds, err := w.watches.removePath(name) - if err != nil { - return err - } - - for _, wd := range wds { - _, err := unix.InotifyRmWatch(w.fd, wd) - if err != nil { - // TODO: Perhaps it's not helpful to return an error here in every - // case; the only two possible errors are: - // - // EBADF, which happens when w.fd is not a valid file descriptor of - // any kind. - // - // EINVAL, which is when fd is not an inotify descriptor or wd is - // not a valid watch descriptor. Watch descriptors are invalidated - // when they are removed explicitly or implicitly; explicitly by - // inotify_rm_watch, implicitly when the file they are watching is - // deleted. - return err - } - } - return nil -} - -func (w *inotify) WatchList() []string { - if w.isClosed() { - return nil - } - - entries := make([]string, 0, w.watches.len()) - w.watches.mu.RLock() - for pathname := range w.watches.path { - entries = append(entries, pathname) - } - w.watches.mu.RUnlock() - - return entries -} - -// readEvents reads from the inotify file descriptor, converts the -// received events into Event objects and sends them via the Events channel -func (w *inotify) readEvents() { - defer func() { - close(w.doneResp) - close(w.Errors) - close(w.Events) - }() - - var ( - buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events - errno error // Syscall errno - ) - for { - // See if we have been closed. - if w.isClosed() { - return - } - - n, err := w.inotifyFile.Read(buf[:]) - switch { - case errors.Unwrap(err) == os.ErrClosed: - return - case err != nil: - if !w.sendError(err) { - return - } - continue - } - - if n < unix.SizeofInotifyEvent { - var err error - if n == 0 { - err = io.EOF // If EOF is received. This should really never happen. - } else if n < 0 { - err = errno // If an error occurred while reading. - } else { - err = errors.New("notify: short read in readEvents()") // Read was too short. - } - if !w.sendError(err) { - return - } - continue - } - - // We don't know how many events we just read into the buffer - // While the offset points to at least one whole event... - var offset uint32 - for offset <= uint32(n-unix.SizeofInotifyEvent) { - var ( - // Point "raw" to the event in the buffer - raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) - mask = uint32(raw.Mask) - nameLen = uint32(raw.Len) - // Move to the next event in the buffer - next = func() { offset += unix.SizeofInotifyEvent + nameLen } - ) - - if mask&unix.IN_Q_OVERFLOW != 0 { - if !w.sendError(ErrEventOverflow) { - return - } - } - - /// If the event happened to the watched directory or the watched - /// file, the kernel doesn't append the filename to the event, but - /// we would like to always fill the the "Name" field with a valid - /// filename. We retrieve the path of the watch from the "paths" - /// map. - watch := w.watches.byWd(uint32(raw.Wd)) - /// Can be nil if Remove() was called in another goroutine for this - /// path inbetween reading the events from the kernel and reading - /// the internal state. Not much we can do about it, so just skip. - /// See #616. - if watch == nil { - next() - continue - } - - name := watch.path - if nameLen > 0 { - /// Point "bytes" at the first byte of the filename - bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen] - /// The filename is padded with NULL bytes. TrimRight() gets rid of those. - name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") - } - - if debug { - internal.Debug(name, raw.Mask, raw.Cookie) - } - - if mask&unix.IN_IGNORED != 0 { //&& event.Op != 0 - next() - continue - } - - // inotify will automatically remove the watch on deletes; just need - // to clean our state here. - if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { - w.watches.remove(watch.wd) - } - - // We can't really update the state when a watched path is moved; - // only IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove - // the watch. - if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF { - if watch.recurse { - next() // Do nothing - continue - } - - err := w.remove(watch.path) - if err != nil && !errors.Is(err, ErrNonExistentWatch) { - if !w.sendError(err) { - return - } - } - } - - /// Skip if we're watching both this path and the parent; the parent - /// will already send a delete so no need to do it twice. - if mask&unix.IN_DELETE_SELF != 0 { - if _, ok := w.watches.path[filepath.Dir(watch.path)]; ok { - next() - continue - } - } - - ev := w.newEvent(name, mask, raw.Cookie) - // Need to update watch path for recurse. - if watch.recurse { - isDir := mask&unix.IN_ISDIR == unix.IN_ISDIR - /// New directory created: set up watch on it. - if isDir && ev.Has(Create) { - err := w.register(ev.Name, watch.flags, true) - if !w.sendError(err) { - return - } - - // This was a directory rename, so we need to update all - // the children. - // - // TODO: this is of course pretty slow; we should use a - // better data structure for storing all of this, e.g. store - // children in the watch. I have some code for this in my - // kqueue refactor we can use in the future. For now I'm - // okay with this as it's not publicly available. - // Correctness first, performance second. - if ev.renamedFrom != "" { - w.watches.mu.Lock() - for k, ww := range w.watches.wd { - if k == watch.wd || ww.path == ev.Name { - continue - } - if strings.HasPrefix(ww.path, ev.renamedFrom) { - ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1) - w.watches.wd[k] = ww - } - } - w.watches.mu.Unlock() - } - } - } - - /// Send the events that are not ignored on the events channel - if !w.sendEvent(ev) { - return - } - next() - } - } -} - -func (w *inotify) isRecursive(path string) bool { - ww := w.watches.byPath(path) - if ww == nil { // path could be a file, so also check the Dir. - ww = w.watches.byPath(filepath.Dir(path)) - } - return ww != nil && ww.recurse -} - -func (w *inotify) newEvent(name string, mask, cookie uint32) Event { - e := Event{Name: name} - if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { - e.Op |= Create - } - if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { - e.Op |= Remove - } - if mask&unix.IN_MODIFY == unix.IN_MODIFY { - e.Op |= Write - } - if mask&unix.IN_OPEN == unix.IN_OPEN { - e.Op |= xUnportableOpen - } - if mask&unix.IN_ACCESS == unix.IN_ACCESS { - e.Op |= xUnportableRead - } - if mask&unix.IN_CLOSE_WRITE == unix.IN_CLOSE_WRITE { - e.Op |= xUnportableCloseWrite - } - if mask&unix.IN_CLOSE_NOWRITE == unix.IN_CLOSE_NOWRITE { - e.Op |= xUnportableCloseRead - } - if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { - e.Op |= Rename - } - if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { - e.Op |= Chmod - } - - if cookie != 0 { - if mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { - w.cookiesMu.Lock() - w.cookies[w.cookieIndex] = koekje{cookie: cookie, path: e.Name} - w.cookieIndex++ - if w.cookieIndex > 9 { - w.cookieIndex = 0 - } - w.cookiesMu.Unlock() - } else if mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { - w.cookiesMu.Lock() - var prev string - for _, c := range w.cookies { - if c.cookie == cookie { - prev = c.path - break - } - } - w.cookiesMu.Unlock() - e.renamedFrom = prev - } - } - return e -} - -func (w *inotify) xSupports(op Op) bool { - return true // Supports everything. -} - -func (w *inotify) state() { - w.watches.mu.Lock() - defer w.watches.mu.Unlock() - for wd, ww := range w.watches.wd { - fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path) - } -} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go deleted file mode 100644 index d8de5ab..0000000 --- a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go +++ /dev/null @@ -1,733 +0,0 @@ -//go:build freebsd || openbsd || netbsd || dragonfly || darwin - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "runtime" - "sync" - "time" - - "github.com/fsnotify/fsnotify/internal" - "golang.org/x/sys/unix" -) - -type kqueue struct { - Events chan Event - Errors chan error - - kq int // File descriptor (as returned by the kqueue() syscall). - closepipe [2]int // Pipe used for closing kq. - watches *watches - done chan struct{} - doneMu sync.Mutex -} - -type ( - watches struct { - mu sync.RWMutex - wd map[int]watch // wd → watch - path map[string]int // pathname → wd - byDir map[string]map[int]struct{} // dirname(path) → wd - seen map[string]struct{} // Keep track of if we know this file exists. - byUser map[string]struct{} // Watches added with Watcher.Add() - } - watch struct { - wd int - name string - linkName string // In case of links; name is the target, and this is the link. - isDir bool - dirFlags uint32 - } -) - -func newWatches() *watches { - return &watches{ - wd: make(map[int]watch), - path: make(map[string]int), - byDir: make(map[string]map[int]struct{}), - seen: make(map[string]struct{}), - byUser: make(map[string]struct{}), - } -} - -func (w *watches) listPaths(userOnly bool) []string { - w.mu.RLock() - defer w.mu.RUnlock() - - if userOnly { - l := make([]string, 0, len(w.byUser)) - for p := range w.byUser { - l = append(l, p) - } - return l - } - - l := make([]string, 0, len(w.path)) - for p := range w.path { - l = append(l, p) - } - return l -} - -func (w *watches) watchesInDir(path string) []string { - w.mu.RLock() - defer w.mu.RUnlock() - - l := make([]string, 0, 4) - for fd := range w.byDir[path] { - info := w.wd[fd] - if _, ok := w.byUser[info.name]; !ok { - l = append(l, info.name) - } - } - return l -} - -// Mark path as added by the user. -func (w *watches) addUserWatch(path string) { - w.mu.Lock() - defer w.mu.Unlock() - w.byUser[path] = struct{}{} -} - -func (w *watches) addLink(path string, fd int) { - w.mu.Lock() - defer w.mu.Unlock() - - w.path[path] = fd - w.seen[path] = struct{}{} -} - -func (w *watches) add(path, linkPath string, fd int, isDir bool) { - w.mu.Lock() - defer w.mu.Unlock() - - w.path[path] = fd - w.wd[fd] = watch{wd: fd, name: path, linkName: linkPath, isDir: isDir} - - parent := filepath.Dir(path) - byDir, ok := w.byDir[parent] - if !ok { - byDir = make(map[int]struct{}, 1) - w.byDir[parent] = byDir - } - byDir[fd] = struct{}{} -} - -func (w *watches) byWd(fd int) (watch, bool) { - w.mu.RLock() - defer w.mu.RUnlock() - info, ok := w.wd[fd] - return info, ok -} - -func (w *watches) byPath(path string) (watch, bool) { - w.mu.RLock() - defer w.mu.RUnlock() - info, ok := w.wd[w.path[path]] - return info, ok -} - -func (w *watches) updateDirFlags(path string, flags uint32) { - w.mu.Lock() - defer w.mu.Unlock() - - fd := w.path[path] - info := w.wd[fd] - info.dirFlags = flags - w.wd[fd] = info -} - -func (w *watches) remove(fd int, path string) bool { - w.mu.Lock() - defer w.mu.Unlock() - - isDir := w.wd[fd].isDir - delete(w.path, path) - delete(w.byUser, path) - - parent := filepath.Dir(path) - delete(w.byDir[parent], fd) - - if len(w.byDir[parent]) == 0 { - delete(w.byDir, parent) - } - - delete(w.wd, fd) - delete(w.seen, path) - return isDir -} - -func (w *watches) markSeen(path string, exists bool) { - w.mu.Lock() - defer w.mu.Unlock() - if exists { - w.seen[path] = struct{}{} - } else { - delete(w.seen, path) - } -} - -func (w *watches) seenBefore(path string) bool { - w.mu.RLock() - defer w.mu.RUnlock() - _, ok := w.seen[path] - return ok -} - -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(0, ev, errs) -} - -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { - kq, closepipe, err := newKqueue() - if err != nil { - return nil, err - } - - w := &kqueue{ - Events: ev, - Errors: errs, - kq: kq, - closepipe: closepipe, - done: make(chan struct{}), - watches: newWatches(), - } - - go w.readEvents() - return w, nil -} - -// newKqueue creates a new kernel event queue and returns a descriptor. -// -// This registers a new event on closepipe, which will trigger an event when -// it's closed. This way we can use kevent() without timeout/polling; without -// the closepipe, it would block forever and we wouldn't be able to stop it at -// all. -func newKqueue() (kq int, closepipe [2]int, err error) { - kq, err = unix.Kqueue() - if kq == -1 { - return kq, closepipe, err - } - - // Register the close pipe. - err = unix.Pipe(closepipe[:]) - if err != nil { - unix.Close(kq) - return kq, closepipe, err - } - unix.CloseOnExec(closepipe[0]) - unix.CloseOnExec(closepipe[1]) - - // Register changes to listen on the closepipe. - changes := make([]unix.Kevent_t, 1) - // SetKevent converts int to the platform-specific types. - unix.SetKevent(&changes[0], closepipe[0], unix.EVFILT_READ, - unix.EV_ADD|unix.EV_ENABLE|unix.EV_ONESHOT) - - ok, err := unix.Kevent(kq, changes, nil, nil) - if ok == -1 { - unix.Close(kq) - unix.Close(closepipe[0]) - unix.Close(closepipe[1]) - return kq, closepipe, err - } - return kq, closepipe, nil -} - -// Returns true if the event was sent, or false if watcher is closed. -func (w *kqueue) sendEvent(e Event) bool { - select { - case <-w.done: - return false - case w.Events <- e: - return true - } -} - -// Returns true if the error was sent, or false if watcher is closed. -func (w *kqueue) sendError(err error) bool { - if err == nil { - return true - } - select { - case <-w.done: - return false - case w.Errors <- err: - return true - } -} - -func (w *kqueue) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - -func (w *kqueue) Close() error { - w.doneMu.Lock() - if w.isClosed() { - w.doneMu.Unlock() - return nil - } - close(w.done) - w.doneMu.Unlock() - - pathsToRemove := w.watches.listPaths(false) - for _, name := range pathsToRemove { - w.Remove(name) - } - - // Send "quit" message to the reader goroutine. - unix.Close(w.closepipe[1]) - return nil -} - -func (w *kqueue) Add(name string) error { return w.AddWith(name) } - -func (w *kqueue) AddWith(name string, opts ...addOpt) error { - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n", - time.Now().Format("15:04:05.000000000"), name) - } - - with := getOptions(opts...) - if !w.xSupports(with.op) { - return fmt.Errorf("%w: %s", xErrUnsupported, with.op) - } - - _, err := w.addWatch(name, noteAllEvents) - if err != nil { - return err - } - w.watches.addUserWatch(name) - return nil -} - -func (w *kqueue) Remove(name string) error { - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n", - time.Now().Format("15:04:05.000000000"), name) - } - return w.remove(name, true) -} - -func (w *kqueue) remove(name string, unwatchFiles bool) error { - if w.isClosed() { - return nil - } - - name = filepath.Clean(name) - info, ok := w.watches.byPath(name) - if !ok { - return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) - } - - err := w.register([]int{info.wd}, unix.EV_DELETE, 0) - if err != nil { - return err - } - - unix.Close(info.wd) - - isDir := w.watches.remove(info.wd, name) - - // Find all watched paths that are in this directory that are not external. - if unwatchFiles && isDir { - pathsToRemove := w.watches.watchesInDir(name) - for _, name := range pathsToRemove { - // Since these are internal, not much sense in propagating error to - // the user, as that will just confuse them with an error about a - // path they did not explicitly watch themselves. - w.Remove(name) - } - } - return nil -} - -func (w *kqueue) WatchList() []string { - if w.isClosed() { - return nil - } - return w.watches.listPaths(true) -} - -// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) -const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME - -// addWatch adds name to the watched file set; the flags are interpreted as -// described in kevent(2). -// -// Returns the real path to the file which was added, with symlinks resolved. -func (w *kqueue) addWatch(name string, flags uint32) (string, error) { - if w.isClosed() { - return "", ErrClosed - } - - name = filepath.Clean(name) - - info, alreadyWatching := w.watches.byPath(name) - if !alreadyWatching { - fi, err := os.Lstat(name) - if err != nil { - return "", err - } - - // Don't watch sockets or named pipes. - if (fi.Mode()&os.ModeSocket == os.ModeSocket) || (fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe) { - return "", nil - } - - // Follow symlinks. - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { - link, err := os.Readlink(name) - if err != nil { - // Return nil because Linux can add unresolvable symlinks to the - // watch list without problems, so maintain consistency with - // that. There will be no file events for broken symlinks. - // TODO: more specific check; returns os.PathError; ENOENT? - return "", nil - } - - _, alreadyWatching = w.watches.byPath(link) - if alreadyWatching { - // Add to watches so we don't get spurious Create events later - // on when we diff the directories. - w.watches.addLink(name, 0) - return link, nil - } - - info.linkName = name - name = link - fi, err = os.Lstat(name) - if err != nil { - return "", nil - } - } - - // Retry on EINTR; open() can return EINTR in practice on macOS. - // See #354, and Go issues 11180 and 39237. - for { - info.wd, err = unix.Open(name, openMode, 0) - if err == nil { - break - } - if errors.Is(err, unix.EINTR) { - continue - } - - return "", err - } - - info.isDir = fi.IsDir() - } - - err := w.register([]int{info.wd}, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE, flags) - if err != nil { - unix.Close(info.wd) - return "", err - } - - if !alreadyWatching { - w.watches.add(name, info.linkName, info.wd, info.isDir) - } - - // Watch the directory if it has not been watched before, or if it was - // watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) - if info.isDir { - watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && - (!alreadyWatching || (info.dirFlags&unix.NOTE_WRITE) != unix.NOTE_WRITE) - w.watches.updateDirFlags(name, flags) - - if watchDir { - if err := w.watchDirectoryFiles(name); err != nil { - return "", err - } - } - } - return name, nil -} - -// readEvents reads from kqueue and converts the received kevents into -// Event values that it sends down the Events channel. -func (w *kqueue) readEvents() { - defer func() { - close(w.Events) - close(w.Errors) - _ = unix.Close(w.kq) - unix.Close(w.closepipe[0]) - }() - - eventBuffer := make([]unix.Kevent_t, 10) - for { - kevents, err := w.read(eventBuffer) - // EINTR is okay, the syscall was interrupted before timeout expired. - if err != nil && err != unix.EINTR { - if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) { - return - } - } - - for _, kevent := range kevents { - var ( - wd = int(kevent.Ident) - mask = uint32(kevent.Fflags) - ) - - // Shut down the loop when the pipe is closed, but only after all - // other events have been processed. - if wd == w.closepipe[0] { - return - } - - path, ok := w.watches.byWd(wd) - if debug { - internal.Debug(path.name, &kevent) - } - - // On macOS it seems that sometimes an event with Ident=0 is - // delivered, and no other flags/information beyond that, even - // though we never saw such a file descriptor. For example in - // TestWatchSymlink/277 (usually at the end, but sometimes sooner): - // - // fmt.Printf("READ: %2d %#v\n", kevent.Ident, kevent) - // unix.Kevent_t{Ident:0x2a, Filter:-4, Flags:0x25, Fflags:0x2, Data:0, Udata:(*uint8)(nil)} - // unix.Kevent_t{Ident:0x0, Filter:-4, Flags:0x25, Fflags:0x2, Data:0, Udata:(*uint8)(nil)} - // - // The first is a normal event, the second with Ident 0. No error - // flag, no data, no ... nothing. - // - // I read a bit through bsd/kern_event.c from the xnu source, but I - // don't really see an obvious location where this is triggered – - // this doesn't seem intentional, but idk... - // - // Technically fd 0 is a valid descriptor, so only skip it if - // there's no path, and if we're on macOS. - if !ok && kevent.Ident == 0 && runtime.GOOS == "darwin" { - continue - } - - event := w.newEvent(path.name, path.linkName, mask) - - if event.Has(Rename) || event.Has(Remove) { - w.remove(event.Name, false) - w.watches.markSeen(event.Name, false) - } - - if path.isDir && event.Has(Write) && !event.Has(Remove) { - w.dirChange(event.Name) - } else if !w.sendEvent(event) { - return - } - - if event.Has(Remove) { - // Look for a file that may have overwritten this; for example, - // mv f1 f2 will delete f2, then create f2. - if path.isDir { - fileDir := filepath.Clean(event.Name) - _, found := w.watches.byPath(fileDir) - if found { - // TODO: this branch is never triggered in any test. - // Added in d6220df (2012). - // isDir check added in 8611c35 (2016): https://github.com/fsnotify/fsnotify/pull/111 - // - // I don't really get how this can be triggered either. - // And it wasn't triggered in the patch that added it, - // either. - // - // Original also had a comment: - // make sure the directory exists before we watch for - // changes. When we do a recursive watch and perform - // rm -rf, the parent directory might have gone - // missing, ignore the missing directory and let the - // upcoming delete event remove the watch from the - // parent directory. - err := w.dirChange(fileDir) - if !w.sendError(err) { - return - } - } - } else { - path := filepath.Clean(event.Name) - if fi, err := os.Lstat(path); err == nil { - err := w.sendCreateIfNew(path, fi) - if !w.sendError(err) { - return - } - } - } - } - } - } -} - -// newEvent returns an platform-independent Event based on kqueue Fflags. -func (w *kqueue) newEvent(name, linkName string, mask uint32) Event { - e := Event{Name: name} - if linkName != "" { - // If the user watched "/path/link" then emit events as "/path/link" - // rather than "/path/target". - e.Name = linkName - } - - if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { - e.Op |= Remove - } - if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { - e.Op |= Write - } - if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { - e.Op |= Rename - } - if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { - e.Op |= Chmod - } - // No point sending a write and delete event at the same time: if it's gone, - // then it's gone. - if e.Op.Has(Write) && e.Op.Has(Remove) { - e.Op &^= Write - } - return e -} - -// watchDirectoryFiles to mimic inotify when adding a watch on a directory -func (w *kqueue) watchDirectoryFiles(dirPath string) error { - files, err := os.ReadDir(dirPath) - if err != nil { - return err - } - - for _, f := range files { - path := filepath.Join(dirPath, f.Name()) - - fi, err := f.Info() - if err != nil { - return fmt.Errorf("%q: %w", path, err) - } - - cleanPath, err := w.internalWatch(path, fi) - if err != nil { - // No permission to read the file; that's not a problem: just skip. - // But do add it to w.fileExists to prevent it from being picked up - // as a "new" file later (it still shows up in the directory - // listing). - switch { - case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM): - cleanPath = filepath.Clean(path) - default: - return fmt.Errorf("%q: %w", path, err) - } - } - - w.watches.markSeen(cleanPath, true) - } - - return nil -} - -// Search the directory for new files and send an event for them. -// -// This functionality is to have the BSD watcher match the inotify, which sends -// a create event for files created in a watched directory. -func (w *kqueue) dirChange(dir string) error { - files, err := os.ReadDir(dir) - if err != nil { - // Directory no longer exists: we can ignore this safely. kqueue will - // still give us the correct events. - if errors.Is(err, os.ErrNotExist) { - return nil - } - return fmt.Errorf("fsnotify.dirChange: %w", err) - } - - for _, f := range files { - fi, err := f.Info() - if err != nil { - return fmt.Errorf("fsnotify.dirChange: %w", err) - } - - err = w.sendCreateIfNew(filepath.Join(dir, fi.Name()), fi) - if err != nil { - // Don't need to send an error if this file isn't readable. - if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) { - return nil - } - return fmt.Errorf("fsnotify.dirChange: %w", err) - } - } - return nil -} - -// Send a create event if the file isn't already being tracked, and start -// watching this file. -func (w *kqueue) sendCreateIfNew(path string, fi os.FileInfo) error { - if !w.watches.seenBefore(path) { - if !w.sendEvent(Event{Name: path, Op: Create}) { - return nil - } - } - - // Like watchDirectoryFiles, but without doing another ReadDir. - path, err := w.internalWatch(path, fi) - if err != nil { - return err - } - w.watches.markSeen(path, true) - return nil -} - -func (w *kqueue) internalWatch(name string, fi os.FileInfo) (string, error) { - if fi.IsDir() { - // mimic Linux providing delete events for subdirectories, but preserve - // the flags used if currently watching subdirectory - info, _ := w.watches.byPath(name) - return w.addWatch(name, info.dirFlags|unix.NOTE_DELETE|unix.NOTE_RENAME) - } - - // watch file to mimic Linux inotify - return w.addWatch(name, noteAllEvents) -} - -// Register events with the queue. -func (w *kqueue) register(fds []int, flags int, fflags uint32) error { - changes := make([]unix.Kevent_t, len(fds)) - for i, fd := range fds { - // SetKevent converts int to the platform-specific types. - unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) - changes[i].Fflags = fflags - } - - // Register the events. - success, err := unix.Kevent(w.kq, changes, nil, nil) - if success == -1 { - return err - } - return nil -} - -// read retrieves pending events, or waits until an event occurs. -func (w *kqueue) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) { - n, err := unix.Kevent(w.kq, nil, events, nil) - if err != nil { - return nil, err - } - return events[0:n], nil -} - -func (w *kqueue) xSupports(op Op) bool { - if runtime.GOOS == "freebsd" { - //return true // Supports everything. - } - if op.Has(xUnportableOpen) || op.Has(xUnportableRead) || - op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) { - return false - } - return true -} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_other.go b/vendor/github.com/fsnotify/fsnotify/backend_other.go deleted file mode 100644 index 5eb5dbc..0000000 --- a/vendor/github.com/fsnotify/fsnotify/backend_other.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows) - -package fsnotify - -import "errors" - -type other struct { - Events chan Event - Errors chan error -} - -func newBackend(ev chan Event, errs chan error) (backend, error) { - return nil, errors.New("fsnotify not supported on the current platform") -} -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { - return newBackend(ev, errs) -} -func (w *other) Close() error { return nil } -func (w *other) WatchList() []string { return nil } -func (w *other) Add(name string) error { return nil } -func (w *other) AddWith(name string, opts ...addOpt) error { return nil } -func (w *other) Remove(name string) error { return nil } -func (w *other) xSupports(op Op) bool { return false } diff --git a/vendor/github.com/fsnotify/fsnotify/backend_windows.go b/vendor/github.com/fsnotify/fsnotify/backend_windows.go deleted file mode 100644 index c54a630..0000000 --- a/vendor/github.com/fsnotify/fsnotify/backend_windows.go +++ /dev/null @@ -1,682 +0,0 @@ -//go:build windows - -// Windows backend based on ReadDirectoryChangesW() -// -// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "reflect" - "runtime" - "strings" - "sync" - "time" - "unsafe" - - "github.com/fsnotify/fsnotify/internal" - "golang.org/x/sys/windows" -) - -type readDirChangesW struct { - Events chan Event - Errors chan error - - port windows.Handle // Handle to completion port - input chan *input // Inputs to the reader are sent on this channel - quit chan chan<- error - - mu sync.Mutex // Protects access to watches, closed - watches watchMap // Map of watches (key: i-number) - closed bool // Set to true when Close() is first called -} - -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(50, ev, errs) -} - -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { - port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) - if err != nil { - return nil, os.NewSyscallError("CreateIoCompletionPort", err) - } - w := &readDirChangesW{ - Events: ev, - Errors: errs, - port: port, - watches: make(watchMap), - input: make(chan *input, 1), - quit: make(chan chan<- error, 1), - } - go w.readEvents() - return w, nil -} - -func (w *readDirChangesW) isClosed() bool { - w.mu.Lock() - defer w.mu.Unlock() - return w.closed -} - -func (w *readDirChangesW) sendEvent(name, renamedFrom string, mask uint64) bool { - if mask == 0 { - return false - } - - event := w.newEvent(name, uint32(mask)) - event.renamedFrom = renamedFrom - select { - case ch := <-w.quit: - w.quit <- ch - case w.Events <- event: - } - return true -} - -// Returns true if the error was sent, or false if watcher is closed. -func (w *readDirChangesW) sendError(err error) bool { - if err == nil { - return true - } - select { - case w.Errors <- err: - return true - case <-w.quit: - return false - } -} - -func (w *readDirChangesW) Close() error { - if w.isClosed() { - return nil - } - - w.mu.Lock() - w.closed = true - w.mu.Unlock() - - // Send "quit" message to the reader goroutine - ch := make(chan error) - w.quit <- ch - if err := w.wakeupReader(); err != nil { - return err - } - return <-ch -} - -func (w *readDirChangesW) Add(name string) error { return w.AddWith(name) } - -func (w *readDirChangesW) AddWith(name string, opts ...addOpt) error { - if w.isClosed() { - return ErrClosed - } - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n", - time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name)) - } - - with := getOptions(opts...) - if !w.xSupports(with.op) { - return fmt.Errorf("%w: %s", xErrUnsupported, with.op) - } - if with.bufsize < 4096 { - return fmt.Errorf("fsnotify.WithBufferSize: buffer size cannot be smaller than 4096 bytes") - } - - in := &input{ - op: opAddWatch, - path: filepath.Clean(name), - flags: sysFSALLEVENTS, - reply: make(chan error), - bufsize: with.bufsize, - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -func (w *readDirChangesW) Remove(name string) error { - if w.isClosed() { - return nil - } - if debug { - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n", - time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name)) - } - - in := &input{ - op: opRemoveWatch, - path: filepath.Clean(name), - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -func (w *readDirChangesW) WatchList() []string { - if w.isClosed() { - return nil - } - - w.mu.Lock() - defer w.mu.Unlock() - - entries := make([]string, 0, len(w.watches)) - for _, entry := range w.watches { - for _, watchEntry := range entry { - for name := range watchEntry.names { - entries = append(entries, filepath.Join(watchEntry.path, name)) - } - // the directory itself is being watched - if watchEntry.mask != 0 { - entries = append(entries, watchEntry.path) - } - } - } - - return entries -} - -// These options are from the old golang.org/x/exp/winfsnotify, where you could -// add various options to the watch. This has long since been removed. -// -// The "sys" in the name is misleading as they're not part of any "system". -// -// This should all be removed at some point, and just use windows.FILE_NOTIFY_* -const ( - sysFSALLEVENTS = 0xfff - sysFSCREATE = 0x100 - sysFSDELETE = 0x200 - sysFSDELETESELF = 0x400 - sysFSMODIFY = 0x2 - sysFSMOVE = 0xc0 - sysFSMOVEDFROM = 0x40 - sysFSMOVEDTO = 0x80 - sysFSMOVESELF = 0x800 - sysFSIGNORED = 0x8000 -) - -func (w *readDirChangesW) newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { - e.Op |= Create - } - if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { - e.Op |= Remove - } - if mask&sysFSMODIFY == sysFSMODIFY { - e.Op |= Write - } - if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { - e.Op |= Rename - } - return e -} - -const ( - opAddWatch = iota - opRemoveWatch -) - -const ( - provisional uint64 = 1 << (32 + iota) -) - -type input struct { - op int - path string - flags uint32 - bufsize int - reply chan error -} - -type inode struct { - handle windows.Handle - volume uint32 - index uint64 -} - -type watch struct { - ov windows.Overlapped - ino *inode // i-number - recurse bool // Recursive watch? - path string // Directory path - mask uint64 // Directory itself is being watched with these notify flags - names map[string]uint64 // Map of names being watched and their notify flags - rename string // Remembers the old name while renaming a file - buf []byte // buffer, allocated later -} - -type ( - indexMap map[uint64]*watch - watchMap map[uint32]indexMap -) - -func (w *readDirChangesW) wakeupReader() error { - err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil) - if err != nil { - return os.NewSyscallError("PostQueuedCompletionStatus", err) - } - return nil -} - -func (w *readDirChangesW) getDir(pathname string) (dir string, err error) { - attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname)) - if err != nil { - return "", os.NewSyscallError("GetFileAttributes", err) - } - if attr&windows.FILE_ATTRIBUTE_DIRECTORY != 0 { - dir = pathname - } else { - dir, _ = filepath.Split(pathname) - dir = filepath.Clean(dir) - } - return -} - -func (w *readDirChangesW) getIno(path string) (ino *inode, err error) { - h, err := windows.CreateFile(windows.StringToUTF16Ptr(path), - windows.FILE_LIST_DIRECTORY, - windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, - nil, windows.OPEN_EXISTING, - windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OVERLAPPED, 0) - if err != nil { - return nil, os.NewSyscallError("CreateFile", err) - } - - var fi windows.ByHandleFileInformation - err = windows.GetFileInformationByHandle(h, &fi) - if err != nil { - windows.CloseHandle(h) - return nil, os.NewSyscallError("GetFileInformationByHandle", err) - } - ino = &inode{ - handle: h, - volume: fi.VolumeSerialNumber, - index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), - } - return ino, nil -} - -// Must run within the I/O thread. -func (m watchMap) get(ino *inode) *watch { - if i := m[ino.volume]; i != nil { - return i[ino.index] - } - return nil -} - -// Must run within the I/O thread. -func (m watchMap) set(ino *inode, watch *watch) { - i := m[ino.volume] - if i == nil { - i = make(indexMap) - m[ino.volume] = i - } - i[ino.index] = watch -} - -// Must run within the I/O thread. -func (w *readDirChangesW) addWatch(pathname string, flags uint64, bufsize int) error { - pathname, recurse := recursivePath(pathname) - - dir, err := w.getDir(pathname) - if err != nil { - return err - } - - ino, err := w.getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watchEntry := w.watches.get(ino) - w.mu.Unlock() - if watchEntry == nil { - _, err := windows.CreateIoCompletionPort(ino.handle, w.port, 0, 0) - if err != nil { - windows.CloseHandle(ino.handle) - return os.NewSyscallError("CreateIoCompletionPort", err) - } - watchEntry = &watch{ - ino: ino, - path: dir, - names: make(map[string]uint64), - recurse: recurse, - buf: make([]byte, bufsize), - } - w.mu.Lock() - w.watches.set(ino, watchEntry) - w.mu.Unlock() - flags |= provisional - } else { - windows.CloseHandle(ino.handle) - } - if pathname == dir { - watchEntry.mask |= flags - } else { - watchEntry.names[filepath.Base(pathname)] |= flags - } - - err = w.startRead(watchEntry) - if err != nil { - return err - } - - if pathname == dir { - watchEntry.mask &= ^provisional - } else { - watchEntry.names[filepath.Base(pathname)] &= ^provisional - } - return nil -} - -// Must run within the I/O thread. -func (w *readDirChangesW) remWatch(pathname string) error { - pathname, recurse := recursivePath(pathname) - - dir, err := w.getDir(pathname) - if err != nil { - return err - } - ino, err := w.getIno(dir) - if err != nil { - return err - } - - w.mu.Lock() - watch := w.watches.get(ino) - w.mu.Unlock() - - if recurse && !watch.recurse { - return fmt.Errorf("can't use \\... with non-recursive watch %q", pathname) - } - - err = windows.CloseHandle(ino.handle) - if err != nil { - w.sendError(os.NewSyscallError("CloseHandle", err)) - } - if watch == nil { - return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname) - } - if pathname == dir { - w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED) - watch.mask = 0 - } else { - name := filepath.Base(pathname) - w.sendEvent(filepath.Join(watch.path, name), "", watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - - return w.startRead(watch) -} - -// Must run within the I/O thread. -func (w *readDirChangesW) deleteWatch(watch *watch) { - for name, mask := range watch.names { - if mask&provisional == 0 { - w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED) - } - delete(watch.names, name) - } - if watch.mask != 0 { - if watch.mask&provisional == 0 { - w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED) - } - watch.mask = 0 - } -} - -// Must run within the I/O thread. -func (w *readDirChangesW) startRead(watch *watch) error { - err := windows.CancelIo(watch.ino.handle) - if err != nil { - w.sendError(os.NewSyscallError("CancelIo", err)) - w.deleteWatch(watch) - } - mask := w.toWindowsFlags(watch.mask) - for _, m := range watch.names { - mask |= w.toWindowsFlags(m) - } - if mask == 0 { - err := windows.CloseHandle(watch.ino.handle) - if err != nil { - w.sendError(os.NewSyscallError("CloseHandle", err)) - } - w.mu.Lock() - delete(w.watches[watch.ino.volume], watch.ino.index) - w.mu.Unlock() - return nil - } - - // We need to pass the array, rather than the slice. - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&watch.buf)) - rdErr := windows.ReadDirectoryChanges(watch.ino.handle, - (*byte)(unsafe.Pointer(hdr.Data)), uint32(hdr.Len), - watch.recurse, mask, nil, &watch.ov, 0) - if rdErr != nil { - err := os.NewSyscallError("ReadDirectoryChanges", rdErr) - if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { - // Watched directory was probably removed - w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF) - err = nil - } - w.deleteWatch(watch) - w.startRead(watch) - return err - } - return nil -} - -// readEvents reads from the I/O completion port, converts the -// received events into Event objects and sends them via the Events channel. -// Entry point to the I/O thread. -func (w *readDirChangesW) readEvents() { - var ( - n uint32 - key uintptr - ov *windows.Overlapped - ) - runtime.LockOSThread() - - for { - // This error is handled after the watch == nil check below. - qErr := windows.GetQueuedCompletionStatus(w.port, &n, &key, &ov, windows.INFINITE) - - watch := (*watch)(unsafe.Pointer(ov)) - if watch == nil { - select { - case ch := <-w.quit: - w.mu.Lock() - var indexes []indexMap - for _, index := range w.watches { - indexes = append(indexes, index) - } - w.mu.Unlock() - for _, index := range indexes { - for _, watch := range index { - w.deleteWatch(watch) - w.startRead(watch) - } - } - - err := windows.CloseHandle(w.port) - if err != nil { - err = os.NewSyscallError("CloseHandle", err) - } - close(w.Events) - close(w.Errors) - ch <- err - return - case in := <-w.input: - switch in.op { - case opAddWatch: - in.reply <- w.addWatch(in.path, uint64(in.flags), in.bufsize) - case opRemoveWatch: - in.reply <- w.remWatch(in.path) - } - default: - } - continue - } - - switch qErr { - case nil: - // No error - case windows.ERROR_MORE_DATA: - if watch == nil { - w.sendError(errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")) - } else { - // The i/o succeeded but the buffer is full. - // In theory we should be building up a full packet. - // In practice we can get away with just carrying on. - n = uint32(unsafe.Sizeof(watch.buf)) - } - case windows.ERROR_ACCESS_DENIED: - // Watched directory was probably removed - w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF) - w.deleteWatch(watch) - w.startRead(watch) - continue - case windows.ERROR_OPERATION_ABORTED: - // CancelIo was called on this handle - continue - default: - w.sendError(os.NewSyscallError("GetQueuedCompletionPort", qErr)) - continue - } - - var offset uint32 - for { - if n == 0 { - w.sendError(ErrEventOverflow) - break - } - - // Point "raw" to the event in the buffer - raw := (*windows.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) - - // Create a buf that is the size of the path name - size := int(raw.FileNameLength / 2) - var buf []uint16 - // TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973 - sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) - sh.Data = uintptr(unsafe.Pointer(&raw.FileName)) - sh.Len = size - sh.Cap = size - name := windows.UTF16ToString(buf) - fullname := filepath.Join(watch.path, name) - - if debug { - internal.Debug(fullname, raw.Action) - } - - var mask uint64 - switch raw.Action { - case windows.FILE_ACTION_REMOVED: - mask = sysFSDELETESELF - case windows.FILE_ACTION_MODIFIED: - mask = sysFSMODIFY - case windows.FILE_ACTION_RENAMED_OLD_NAME: - watch.rename = name - case windows.FILE_ACTION_RENAMED_NEW_NAME: - // Update saved path of all sub-watches. - old := filepath.Join(watch.path, watch.rename) - w.mu.Lock() - for _, watchMap := range w.watches { - for _, ww := range watchMap { - if strings.HasPrefix(ww.path, old) { - ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old)) - } - } - } - w.mu.Unlock() - - if watch.names[watch.rename] != 0 { - watch.names[name] |= watch.names[watch.rename] - delete(watch.names, watch.rename) - mask = sysFSMOVESELF - } - } - - if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME { - w.sendEvent(fullname, "", watch.names[name]&mask) - } - if raw.Action == windows.FILE_ACTION_REMOVED { - w.sendEvent(fullname, "", watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - - if watch.rename != "" && raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME { - w.sendEvent(fullname, filepath.Join(watch.path, watch.rename), watch.mask&w.toFSnotifyFlags(raw.Action)) - } else { - w.sendEvent(fullname, "", watch.mask&w.toFSnotifyFlags(raw.Action)) - } - - if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME { - w.sendEvent(filepath.Join(watch.path, watch.rename), "", watch.names[name]&mask) - } - - // Move to the next event in the buffer - if raw.NextEntryOffset == 0 { - break - } - offset += raw.NextEntryOffset - - // Error! - if offset >= n { - //lint:ignore ST1005 Windows should be capitalized - w.sendError(errors.New("Windows system assumed buffer larger than it is, events have likely been missed")) - break - } - } - - if err := w.startRead(watch); err != nil { - w.sendError(err) - } - } -} - -func (w *readDirChangesW) toWindowsFlags(mask uint64) uint32 { - var m uint32 - if mask&sysFSMODIFY != 0 { - m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE - } - if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { - m |= windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME - } - return m -} - -func (w *readDirChangesW) toFSnotifyFlags(action uint32) uint64 { - switch action { - case windows.FILE_ACTION_ADDED: - return sysFSCREATE - case windows.FILE_ACTION_REMOVED: - return sysFSDELETE - case windows.FILE_ACTION_MODIFIED: - return sysFSMODIFY - case windows.FILE_ACTION_RENAMED_OLD_NAME: - return sysFSMOVEDFROM - case windows.FILE_ACTION_RENAMED_NEW_NAME: - return sysFSMOVEDTO - } - return 0 -} - -func (w *readDirChangesW) xSupports(op Op) bool { - if op.Has(xUnportableOpen) || op.Has(xUnportableRead) || - op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) { - return false - } - return true -} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go deleted file mode 100644 index 0760efe..0000000 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go +++ /dev/null @@ -1,494 +0,0 @@ -// Package fsnotify provides a cross-platform interface for file system -// notifications. -// -// Currently supported systems: -// -// - Linux via inotify -// - BSD, macOS via kqueue -// - Windows via ReadDirectoryChangesW -// - illumos via FEN -// -// # FSNOTIFY_DEBUG -// -// Set the FSNOTIFY_DEBUG environment variable to "1" to print debug messages to -// stderr. This can be useful to track down some problems, especially in cases -// where fsnotify is used as an indirect dependency. -// -// Every event will be printed as soon as there's something useful to print, -// with as little processing from fsnotify. -// -// Example output: -// -// FSNOTIFY_DEBUG: 11:34:23.633087586 256:IN_CREATE → "/tmp/file-1" -// FSNOTIFY_DEBUG: 11:34:23.633202319 4:IN_ATTRIB → "/tmp/file-1" -// FSNOTIFY_DEBUG: 11:34:28.989728764 512:IN_DELETE → "/tmp/file-1" -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "strings" -) - -// Watcher watches a set of paths, delivering events on a channel. -// -// A watcher should not be copied (e.g. pass it by pointer, rather than by -// value). -// -// # Linux notes -// -// When a file is removed a Remove event won't be emitted until all file -// descriptors are closed, and deletes will always emit a Chmod. For example: -// -// fp := os.Open("file") -// os.Remove("file") // Triggers Chmod -// fp.Close() // Triggers Remove -// -// This is the event that inotify sends, so not much can be changed about this. -// -// The fs.inotify.max_user_watches sysctl variable specifies the upper limit -// for the number of watches per user, and fs.inotify.max_user_instances -// specifies the maximum number of inotify instances per user. Every Watcher you -// create is an "instance", and every path you add is a "watch". -// -// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and -// /proc/sys/fs/inotify/max_user_instances -// -// To increase them you can use sysctl or write the value to the /proc file: -// -// # Default values on Linux 5.18 -// sysctl fs.inotify.max_user_watches=124983 -// sysctl fs.inotify.max_user_instances=128 -// -// To make the changes persist on reboot edit /etc/sysctl.conf or -// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check -// your distro's documentation): -// -// fs.inotify.max_user_watches=124983 -// fs.inotify.max_user_instances=128 -// -// Reaching the limit will result in a "no space left on device" or "too many open -// files" error. -// -// # kqueue notes (macOS, BSD) -// -// kqueue requires opening a file descriptor for every file that's being watched; -// so if you're watching a directory with five files then that's six file -// descriptors. You will run in to your system's "max open files" limit faster on -// these platforms. -// -// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to -// control the maximum number of open files, as well as /etc/login.conf on BSD -// systems. -// -// # Windows notes -// -// Paths can be added as "C:\\path\\to\\dir", but forward slashes -// ("C:/path/to/dir") will also work. -// -// When a watched directory is removed it will always send an event for the -// directory itself, but may not send events for all files in that directory. -// Sometimes it will send events for all files, sometimes it will send no -// events, and often only for some files. -// -// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest -// value that is guaranteed to work with SMB filesystems. If you have many -// events in quick succession this may not be enough, and you will have to use -// [WithBufferSize] to increase the value. -type Watcher struct { - b backend - - // Events sends the filesystem change events. - // - // fsnotify can send the following events; a "path" here can refer to a - // file, directory, symbolic link, or special file like a FIFO. - // - // fsnotify.Create A new path was created; this may be followed by one - // or more Write events if data also gets written to a - // file. - // - // fsnotify.Remove A path was removed. - // - // fsnotify.Rename A path was renamed. A rename is always sent with the - // old path as Event.Name, and a Create event will be - // sent with the new name. Renames are only sent for - // paths that are currently watched; e.g. moving an - // unmonitored file into a monitored directory will - // show up as just a Create. Similarly, renaming a file - // to outside a monitored directory will show up as - // only a Rename. - // - // fsnotify.Write A file or named pipe was written to. A Truncate will - // also trigger a Write. A single "write action" - // initiated by the user may show up as one or multiple - // writes, depending on when the system syncs things to - // disk. For example when compiling a large Go program - // you may get hundreds of Write events, and you may - // want to wait until you've stopped receiving them - // (see the dedup example in cmd/fsnotify). - // - // Some systems may send Write event for directories - // when the directory content changes. - // - // fsnotify.Chmod Attributes were changed. On Linux this is also sent - // when a file is removed (or more accurately, when a - // link to an inode is removed). On kqueue it's sent - // when a file is truncated. On Windows it's never - // sent. - Events chan Event - - // Errors sends any errors. - Errors chan error -} - -// Event represents a file system notification. -type Event struct { - // Path to the file or directory. - // - // Paths are relative to the input; for example with Add("dir") the Name - // will be set to "dir/file" if you create that file, but if you use - // Add("/path/to/dir") it will be "/path/to/dir/file". - Name string - - // File operation that triggered the event. - // - // This is a bitmask and some systems may send multiple operations at once. - // Use the Event.Has() method instead of comparing with ==. - Op Op - - // Create events will have this set to the old path if it's a rename. This - // only works when both the source and destination are watched. It's not - // reliable when watching individual files, only directories. - // - // For example "mv /tmp/file /tmp/rename" will emit: - // - // Event{Op: Rename, Name: "/tmp/file"} - // Event{Op: Create, Name: "/tmp/rename", RenamedFrom: "/tmp/file"} - renamedFrom string -} - -// Op describes a set of file operations. -type Op uint32 - -// The operations fsnotify can trigger; see the documentation on [Watcher] for a -// full description, and check them with [Event.Has]. -const ( - // A new pathname was created. - Create Op = 1 << iota - - // The pathname was written to; this does *not* mean the write has finished, - // and a write can be followed by more writes. - Write - - // The path was removed; any watches on it will be removed. Some "remove" - // operations may trigger a Rename if the file is actually moved (for - // example "remove to trash" is often a rename). - Remove - - // The path was renamed to something else; any watches on it will be - // removed. - Rename - - // File attributes were changed. - // - // It's generally not recommended to take action on this event, as it may - // get triggered very frequently by some software. For example, Spotlight - // indexing on macOS, anti-virus software, backup software, etc. - Chmod - - // File descriptor was opened. - // - // Only works on Linux and FreeBSD. - xUnportableOpen - - // File was read from. - // - // Only works on Linux and FreeBSD. - xUnportableRead - - // File opened for writing was closed. - // - // Only works on Linux and FreeBSD. - // - // The advantage of using this over Write is that it's more reliable than - // waiting for Write events to stop. It's also faster (if you're not - // listening to Write events): copying a file of a few GB can easily - // generate tens of thousands of Write events in a short span of time. - xUnportableCloseWrite - - // File opened for reading was closed. - // - // Only works on Linux and FreeBSD. - xUnportableCloseRead -) - -var ( - // ErrNonExistentWatch is used when Remove() is called on a path that's not - // added. - ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch") - - // ErrClosed is used when trying to operate on a closed Watcher. - ErrClosed = errors.New("fsnotify: watcher already closed") - - // ErrEventOverflow is reported from the Errors channel when there are too - // many events: - // - // - inotify: inotify returns IN_Q_OVERFLOW – because there are too - // many queued events (the fs.inotify.max_queued_events - // sysctl can be used to increase this). - // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. - // - kqueue, fen: Not used. - ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow") - - // ErrUnsupported is returned by AddWith() when WithOps() specified an - // Unportable event that's not supported on this platform. - xErrUnsupported = errors.New("fsnotify: not supported with this backend") -) - -// NewWatcher creates a new Watcher. -func NewWatcher() (*Watcher, error) { - ev, errs := make(chan Event), make(chan error) - b, err := newBackend(ev, errs) - if err != nil { - return nil, err - } - return &Watcher{b: b, Events: ev, Errors: errs}, nil -} - -// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events -// channel. -// -// The main use case for this is situations with a very large number of events -// where the kernel buffer size can't be increased (e.g. due to lack of -// permissions). An unbuffered Watcher will perform better for almost all use -// cases, and whenever possible you will be better off increasing the kernel -// buffers instead of adding a large userspace buffer. -func NewBufferedWatcher(sz uint) (*Watcher, error) { - ev, errs := make(chan Event), make(chan error) - b, err := newBufferedBackend(sz, ev, errs) - if err != nil { - return nil, err - } - return &Watcher{b: b, Events: ev, Errors: errs}, nil -} - -// Add starts monitoring the path for changes. -// -// A path can only be watched once; watching it more than once is a no-op and will -// not return an error. Paths that do not yet exist on the filesystem cannot be -// watched. -// -// A watch will be automatically removed if the watched path is deleted or -// renamed. The exception is the Windows backend, which doesn't remove the -// watcher on renames. -// -// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special -// filesystems (/proc, /sys, etc.) generally don't work. -// -// Returns [ErrClosed] if [Watcher.Close] was called. -// -// See [Watcher.AddWith] for a version that allows adding options. -// -// # Watching directories -// -// All files in a directory are monitored, including new files that are created -// after the watcher is started. Subdirectories are not watched (i.e. it's -// non-recursive). -// -// # Watching files -// -// Watching individual files (rather than directories) is generally not -// recommended as many programs (especially editors) update files atomically: it -// will write to a temporary file which is then moved to destination, -// overwriting the original (or some variant thereof). The watcher on the -// original file is now lost, as that no longer exists. -// -// The upshot of this is that a power failure or crash won't leave a -// half-written file. -// -// Watch the parent directory and use Event.Name to filter out files you're not -// interested in. There is an example of this in cmd/fsnotify/file.go. -func (w *Watcher) Add(path string) error { return w.b.Add(path) } - -// AddWith is like [Watcher.Add], but allows adding options. When using Add() -// the defaults described below are used. -// -// Possible options are: -// -// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on -// other platforms. The default is 64K (65536 bytes). -func (w *Watcher) AddWith(path string, opts ...addOpt) error { return w.b.AddWith(path, opts...) } - -// Remove stops monitoring the path for changes. -// -// Directories are always removed non-recursively. For example, if you added -// /tmp/dir and /tmp/dir/subdir then you will need to remove both. -// -// Removing a path that has not yet been added returns [ErrNonExistentWatch]. -// -// Returns nil if [Watcher.Close] was called. -func (w *Watcher) Remove(path string) error { return w.b.Remove(path) } - -// Close removes all watches and closes the Events channel. -func (w *Watcher) Close() error { return w.b.Close() } - -// WatchList returns all paths explicitly added with [Watcher.Add] (and are not -// yet removed). -// -// Returns nil if [Watcher.Close] was called. -func (w *Watcher) WatchList() []string { return w.b.WatchList() } - -// Supports reports if all the listed operations are supported by this platform. -// -// Create, Write, Remove, Rename, and Chmod are always supported. It can only -// return false for an Op starting with Unportable. -func (w *Watcher) xSupports(op Op) bool { return w.b.xSupports(op) } - -func (o Op) String() string { - var b strings.Builder - if o.Has(Create) { - b.WriteString("|CREATE") - } - if o.Has(Remove) { - b.WriteString("|REMOVE") - } - if o.Has(Write) { - b.WriteString("|WRITE") - } - if o.Has(xUnportableOpen) { - b.WriteString("|OPEN") - } - if o.Has(xUnportableRead) { - b.WriteString("|READ") - } - if o.Has(xUnportableCloseWrite) { - b.WriteString("|CLOSE_WRITE") - } - if o.Has(xUnportableCloseRead) { - b.WriteString("|CLOSE_READ") - } - if o.Has(Rename) { - b.WriteString("|RENAME") - } - if o.Has(Chmod) { - b.WriteString("|CHMOD") - } - if b.Len() == 0 { - return "[no events]" - } - return b.String()[1:] -} - -// Has reports if this operation has the given operation. -func (o Op) Has(h Op) bool { return o&h != 0 } - -// Has reports if this event has the given operation. -func (e Event) Has(op Op) bool { return e.Op.Has(op) } - -// String returns a string representation of the event with their path. -func (e Event) String() string { - if e.renamedFrom != "" { - return fmt.Sprintf("%-13s %q ← %q", e.Op.String(), e.Name, e.renamedFrom) - } - return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name) -} - -type ( - backend interface { - Add(string) error - AddWith(string, ...addOpt) error - Remove(string) error - WatchList() []string - Close() error - xSupports(Op) bool - } - addOpt func(opt *withOpts) - withOpts struct { - bufsize int - op Op - noFollow bool - sendCreate bool - } -) - -var debug = func() bool { - // Check for exactly "1" (rather than mere existence) so we can add - // options/flags in the future. I don't know if we ever want that, but it's - // nice to leave the option open. - return os.Getenv("FSNOTIFY_DEBUG") == "1" -}() - -var defaultOpts = withOpts{ - bufsize: 65536, // 64K - op: Create | Write | Remove | Rename | Chmod, -} - -func getOptions(opts ...addOpt) withOpts { - with := defaultOpts - for _, o := range opts { - if o != nil { - o(&with) - } - } - return with -} - -// WithBufferSize sets the [ReadDirectoryChangesW] buffer size. -// -// This only has effect on Windows systems, and is a no-op for other backends. -// -// The default value is 64K (65536 bytes) which is the highest value that works -// on all filesystems and should be enough for most applications, but if you -// have a large burst of events it may not be enough. You can increase it if -// you're hitting "queue or buffer overflow" errors ([ErrEventOverflow]). -// -// [ReadDirectoryChangesW]: https://learn.microsoft.com/en-gb/windows/win32/api/winbase/nf-winbase-readdirectorychangesw -func WithBufferSize(bytes int) addOpt { - return func(opt *withOpts) { opt.bufsize = bytes } -} - -// WithOps sets which operations to listen for. The default is [Create], -// [Write], [Remove], [Rename], and [Chmod]. -// -// Excluding operations you're not interested in can save quite a bit of CPU -// time; in some use cases there may be hundreds of thousands of useless Write -// or Chmod operations per second. -// -// This can also be used to add unportable operations not supported by all -// platforms; unportable operations all start with "Unportable": -// [UnportableOpen], [UnportableRead], [UnportableCloseWrite], and -// [UnportableCloseRead]. -// -// AddWith returns an error when using an unportable operation that's not -// supported. Use [Watcher.Support] to check for support. -func withOps(op Op) addOpt { - return func(opt *withOpts) { opt.op = op } -} - -// WithNoFollow disables following symlinks, so the symlinks themselves are -// watched. -func withNoFollow() addOpt { - return func(opt *withOpts) { opt.noFollow = true } -} - -// "Internal" option for recursive watches on inotify. -func withCreate() addOpt { - return func(opt *withOpts) { opt.sendCreate = true } -} - -var enableRecurse = false - -// Check if this path is recursive (ends with "/..." or "\..."), and return the -// path with the /... stripped. -func recursivePath(path string) (string, bool) { - path = filepath.Clean(path) - if !enableRecurse { // Only enabled in tests for now. - return path, false - } - if filepath.Base(path) == "..." { - return filepath.Dir(path), true - } - return path, false -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/darwin.go b/vendor/github.com/fsnotify/fsnotify/internal/darwin.go deleted file mode 100644 index b0eab10..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/darwin.go +++ /dev/null @@ -1,39 +0,0 @@ -//go:build darwin - -package internal - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -var ( - SyscallEACCES = syscall.EACCES - UnixEACCES = unix.EACCES -) - -var maxfiles uint64 - -// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/ -func SetRlimit() { - var l syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l) - if err == nil && l.Cur != l.Max { - l.Cur = l.Max - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l) - } - maxfiles = l.Cur - - if n, err := syscall.SysctlUint32("kern.maxfiles"); err == nil && uint64(n) < maxfiles { - maxfiles = uint64(n) - } - - if n, err := syscall.SysctlUint32("kern.maxfilesperproc"); err == nil && uint64(n) < maxfiles { - maxfiles = uint64(n) - } -} - -func Maxfiles() uint64 { return maxfiles } -func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) } -func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go deleted file mode 100644 index 928319f..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go +++ /dev/null @@ -1,57 +0,0 @@ -package internal - -import "golang.org/x/sys/unix" - -var names = []struct { - n string - m uint32 -}{ - {"NOTE_ABSOLUTE", unix.NOTE_ABSOLUTE}, - {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_BACKGROUND", unix.NOTE_BACKGROUND}, - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_CRITICAL", unix.NOTE_CRITICAL}, - {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, - {"NOTE_EXITSTATUS", unix.NOTE_EXITSTATUS}, - {"NOTE_EXIT_CSERROR", unix.NOTE_EXIT_CSERROR}, - {"NOTE_EXIT_DECRYPTFAIL", unix.NOTE_EXIT_DECRYPTFAIL}, - {"NOTE_EXIT_DETAIL", unix.NOTE_EXIT_DETAIL}, - {"NOTE_EXIT_DETAIL_MASK", unix.NOTE_EXIT_DETAIL_MASK}, - {"NOTE_EXIT_MEMORY", unix.NOTE_EXIT_MEMORY}, - {"NOTE_EXIT_REPARENTED", unix.NOTE_EXIT_REPARENTED}, - {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FFAND", unix.NOTE_FFAND}, - {"NOTE_FFCOPY", unix.NOTE_FFCOPY}, - {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK}, - {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK}, - {"NOTE_FFNOP", unix.NOTE_FFNOP}, - {"NOTE_FFOR", unix.NOTE_FFOR}, - {"NOTE_FORK", unix.NOTE_FORK}, - {"NOTE_FUNLOCK", unix.NOTE_FUNLOCK}, - {"NOTE_LEEWAY", unix.NOTE_LEEWAY}, - {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_MACHTIME", unix.NOTE_MACHTIME}, - {"NOTE_MACH_CONTINUOUS_TIME", unix.NOTE_MACH_CONTINUOUS_TIME}, - {"NOTE_NONE", unix.NOTE_NONE}, - {"NOTE_NSECONDS", unix.NOTE_NSECONDS}, - {"NOTE_OOB", unix.NOTE_OOB}, - //{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, -0x100000 (?!) - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_REAP", unix.NOTE_REAP}, - {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_SECONDS", unix.NOTE_SECONDS}, - {"NOTE_SIGNAL", unix.NOTE_SIGNAL}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRIGGER", unix.NOTE_TRIGGER}, - {"NOTE_USECONDS", unix.NOTE_USECONDS}, - {"NOTE_VM_ERROR", unix.NOTE_VM_ERROR}, - {"NOTE_VM_PRESSURE", unix.NOTE_VM_PRESSURE}, - {"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", unix.NOTE_VM_PRESSURE_SUDDEN_TERMINATE}, - {"NOTE_VM_PRESSURE_TERMINATE", unix.NOTE_VM_PRESSURE_TERMINATE}, - {"NOTE_WRITE", unix.NOTE_WRITE}, -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go deleted file mode 100644 index 3186b0c..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go +++ /dev/null @@ -1,33 +0,0 @@ -package internal - -import "golang.org/x/sys/unix" - -var names = []struct { - n string - m uint32 -}{ - {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, - {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FFAND", unix.NOTE_FFAND}, - {"NOTE_FFCOPY", unix.NOTE_FFCOPY}, - {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK}, - {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK}, - {"NOTE_FFNOP", unix.NOTE_FFNOP}, - {"NOTE_FFOR", unix.NOTE_FFOR}, - {"NOTE_FORK", unix.NOTE_FORK}, - {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_OOB", unix.NOTE_OOB}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRIGGER", unix.NOTE_TRIGGER}, - {"NOTE_WRITE", unix.NOTE_WRITE}, -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go deleted file mode 100644 index f69fdb9..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go +++ /dev/null @@ -1,42 +0,0 @@ -package internal - -import "golang.org/x/sys/unix" - -var names = []struct { - n string - m uint32 -}{ - {"NOTE_ABSTIME", unix.NOTE_ABSTIME}, - {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_CLOSE", unix.NOTE_CLOSE}, - {"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE}, - {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, - {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FFAND", unix.NOTE_FFAND}, - {"NOTE_FFCOPY", unix.NOTE_FFCOPY}, - {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK}, - {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK}, - {"NOTE_FFNOP", unix.NOTE_FFNOP}, - {"NOTE_FFOR", unix.NOTE_FFOR}, - {"NOTE_FILE_POLL", unix.NOTE_FILE_POLL}, - {"NOTE_FORK", unix.NOTE_FORK}, - {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_MSECONDS", unix.NOTE_MSECONDS}, - {"NOTE_NSECONDS", unix.NOTE_NSECONDS}, - {"NOTE_OPEN", unix.NOTE_OPEN}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_READ", unix.NOTE_READ}, - {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_SECONDS", unix.NOTE_SECONDS}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRIGGER", unix.NOTE_TRIGGER}, - {"NOTE_USECONDS", unix.NOTE_USECONDS}, - {"NOTE_WRITE", unix.NOTE_WRITE}, -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go deleted file mode 100644 index 607e683..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go +++ /dev/null @@ -1,32 +0,0 @@ -//go:build freebsd || openbsd || netbsd || dragonfly || darwin - -package internal - -import ( - "fmt" - "os" - "strings" - "time" - - "golang.org/x/sys/unix" -) - -func Debug(name string, kevent *unix.Kevent_t) { - mask := uint32(kevent.Fflags) - - var ( - l []string - unknown = mask - ) - for _, n := range names { - if mask&n.m == n.m { - l = append(l, n.n) - unknown ^= n.m - } - } - if unknown > 0 { - l = append(l, fmt.Sprintf("0x%x", unknown)) - } - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-60s → %q\n", - time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name) -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go deleted file mode 100644 index 35c734b..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go +++ /dev/null @@ -1,56 +0,0 @@ -package internal - -import ( - "fmt" - "os" - "strings" - "time" - - "golang.org/x/sys/unix" -) - -func Debug(name string, mask, cookie uint32) { - names := []struct { - n string - m uint32 - }{ - {"IN_ACCESS", unix.IN_ACCESS}, - {"IN_ATTRIB", unix.IN_ATTRIB}, - {"IN_CLOSE", unix.IN_CLOSE}, - {"IN_CLOSE_NOWRITE", unix.IN_CLOSE_NOWRITE}, - {"IN_CLOSE_WRITE", unix.IN_CLOSE_WRITE}, - {"IN_CREATE", unix.IN_CREATE}, - {"IN_DELETE", unix.IN_DELETE}, - {"IN_DELETE_SELF", unix.IN_DELETE_SELF}, - {"IN_IGNORED", unix.IN_IGNORED}, - {"IN_ISDIR", unix.IN_ISDIR}, - {"IN_MODIFY", unix.IN_MODIFY}, - {"IN_MOVE", unix.IN_MOVE}, - {"IN_MOVED_FROM", unix.IN_MOVED_FROM}, - {"IN_MOVED_TO", unix.IN_MOVED_TO}, - {"IN_MOVE_SELF", unix.IN_MOVE_SELF}, - {"IN_OPEN", unix.IN_OPEN}, - {"IN_Q_OVERFLOW", unix.IN_Q_OVERFLOW}, - {"IN_UNMOUNT", unix.IN_UNMOUNT}, - } - - var ( - l []string - unknown = mask - ) - for _, n := range names { - if mask&n.m == n.m { - l = append(l, n.n) - unknown ^= n.m - } - } - if unknown > 0 { - l = append(l, fmt.Sprintf("0x%x", unknown)) - } - var c string - if cookie > 0 { - c = fmt.Sprintf("(cookie: %d) ", cookie) - } - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %-30s → %s%q\n", - time.Now().Format("15:04:05.000000000"), strings.Join(l, "|"), c, name) -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go deleted file mode 100644 index e5b3b6f..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go +++ /dev/null @@ -1,25 +0,0 @@ -package internal - -import "golang.org/x/sys/unix" - -var names = []struct { - n string - m uint32 -}{ - {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, - {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FORK", unix.NOTE_FORK}, - {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_WRITE", unix.NOTE_WRITE}, -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go deleted file mode 100644 index 1dd455b..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go +++ /dev/null @@ -1,28 +0,0 @@ -package internal - -import "golang.org/x/sys/unix" - -var names = []struct { - n string - m uint32 -}{ - {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - // {"NOTE_CHANGE", unix.NOTE_CHANGE}, // Not on 386? - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EOF", unix.NOTE_EOF}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, - {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FORK", unix.NOTE_FORK}, - {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRUNCATE", unix.NOTE_TRUNCATE}, - {"NOTE_WRITE", unix.NOTE_WRITE}, -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go deleted file mode 100644 index f1b2e73..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go +++ /dev/null @@ -1,45 +0,0 @@ -package internal - -import ( - "fmt" - "os" - "strings" - "time" - - "golang.org/x/sys/unix" -) - -func Debug(name string, mask int32) { - names := []struct { - n string - m int32 - }{ - {"FILE_ACCESS", unix.FILE_ACCESS}, - {"FILE_MODIFIED", unix.FILE_MODIFIED}, - {"FILE_ATTRIB", unix.FILE_ATTRIB}, - {"FILE_TRUNC", unix.FILE_TRUNC}, - {"FILE_NOFOLLOW", unix.FILE_NOFOLLOW}, - {"FILE_DELETE", unix.FILE_DELETE}, - {"FILE_RENAME_TO", unix.FILE_RENAME_TO}, - {"FILE_RENAME_FROM", unix.FILE_RENAME_FROM}, - {"UNMOUNTED", unix.UNMOUNTED}, - {"MOUNTEDOVER", unix.MOUNTEDOVER}, - {"FILE_EXCEPTION", unix.FILE_EXCEPTION}, - } - - var ( - l []string - unknown = mask - ) - for _, n := range names { - if mask&n.m == n.m { - l = append(l, n.n) - unknown ^= n.m - } - } - if unknown > 0 { - l = append(l, fmt.Sprintf("0x%x", unknown)) - } - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-30s → %q\n", - time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name) -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go deleted file mode 100644 index 52bf4ce..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go +++ /dev/null @@ -1,40 +0,0 @@ -package internal - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "time" - - "golang.org/x/sys/windows" -) - -func Debug(name string, mask uint32) { - names := []struct { - n string - m uint32 - }{ - {"FILE_ACTION_ADDED", windows.FILE_ACTION_ADDED}, - {"FILE_ACTION_REMOVED", windows.FILE_ACTION_REMOVED}, - {"FILE_ACTION_MODIFIED", windows.FILE_ACTION_MODIFIED}, - {"FILE_ACTION_RENAMED_OLD_NAME", windows.FILE_ACTION_RENAMED_OLD_NAME}, - {"FILE_ACTION_RENAMED_NEW_NAME", windows.FILE_ACTION_RENAMED_NEW_NAME}, - } - - var ( - l []string - unknown = mask - ) - for _, n := range names { - if mask&n.m == n.m { - l = append(l, n.n) - unknown ^= n.m - } - } - if unknown > 0 { - l = append(l, fmt.Sprintf("0x%x", unknown)) - } - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %-65s → %q\n", - time.Now().Format("15:04:05.000000000"), strings.Join(l, " | "), filepath.ToSlash(name)) -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go b/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go deleted file mode 100644 index 547df1d..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build freebsd - -package internal - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -var ( - SyscallEACCES = syscall.EACCES - UnixEACCES = unix.EACCES -) - -var maxfiles uint64 - -func SetRlimit() { - // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/ - var l syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l) - if err == nil && l.Cur != l.Max { - l.Cur = l.Max - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l) - } - maxfiles = uint64(l.Cur) -} - -func Maxfiles() uint64 { return maxfiles } -func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) } -func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, uint64(dev)) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/internal.go b/vendor/github.com/fsnotify/fsnotify/internal/internal.go deleted file mode 100644 index 7daa45e..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/internal.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package internal contains some helpers. -package internal diff --git a/vendor/github.com/fsnotify/fsnotify/internal/unix.go b/vendor/github.com/fsnotify/fsnotify/internal/unix.go deleted file mode 100644 index 30976ce..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/unix.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build !windows && !darwin && !freebsd - -package internal - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -var ( - SyscallEACCES = syscall.EACCES - UnixEACCES = unix.EACCES -) - -var maxfiles uint64 - -func SetRlimit() { - // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/ - var l syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l) - if err == nil && l.Cur != l.Max { - l.Cur = l.Max - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l) - } - maxfiles = uint64(l.Cur) -} - -func Maxfiles() uint64 { return maxfiles } -func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) } -func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/unix2.go b/vendor/github.com/fsnotify/fsnotify/internal/unix2.go deleted file mode 100644 index 37dfedd..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/unix2.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !windows - -package internal - -func HasPrivilegesForSymlink() bool { - return true -} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/windows.go b/vendor/github.com/fsnotify/fsnotify/internal/windows.go deleted file mode 100644 index a72c649..0000000 --- a/vendor/github.com/fsnotify/fsnotify/internal/windows.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build windows - -package internal - -import ( - "errors" - - "golang.org/x/sys/windows" -) - -// Just a dummy. -var ( - SyscallEACCES = errors.New("dummy") - UnixEACCES = errors.New("dummy") -) - -func SetRlimit() {} -func Maxfiles() uint64 { return 1<<64 - 1 } -func Mkfifo(path string, mode uint32) error { return errors.New("no FIFOs on Windows") } -func Mknod(path string, mode uint32, dev int) error { return errors.New("no device nodes on Windows") } - -func HasPrivilegesForSymlink() bool { - var sid *windows.SID - err := windows.AllocateAndInitializeSid( - &windows.SECURITY_NT_AUTHORITY, - 2, - windows.SECURITY_BUILTIN_DOMAIN_RID, - windows.DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &sid) - if err != nil { - return false - } - defer windows.FreeSid(sid) - token := windows.Token(0) - member, err := token.IsMember(sid) - if err != nil { - return false - } - return member || token.IsElevated() -} diff --git a/vendor/github.com/fsnotify/fsnotify/system_bsd.go b/vendor/github.com/fsnotify/fsnotify/system_bsd.go deleted file mode 100644 index f65e8fe..0000000 --- a/vendor/github.com/fsnotify/fsnotify/system_bsd.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build freebsd || openbsd || netbsd || dragonfly - -package fsnotify - -import "golang.org/x/sys/unix" - -const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/system_darwin.go b/vendor/github.com/fsnotify/fsnotify/system_darwin.go deleted file mode 100644 index a29fc7a..0000000 --- a/vendor/github.com/fsnotify/fsnotify/system_darwin.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build darwin - -package fsnotify - -import "golang.org/x/sys/unix" - -// note: this constant is not defined on BSD -const openMode = unix.O_EVTONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/go-chi/chi/.gitignore b/vendor/github.com/go-chi/chi/.gitignore deleted file mode 100644 index ba22c99..0000000 --- a/vendor/github.com/go-chi/chi/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.idea -*.sw? -.vscode diff --git a/vendor/github.com/go-chi/chi/.travis.yml b/vendor/github.com/go-chi/chi/.travis.yml deleted file mode 100644 index 44ecf0d..0000000 --- a/vendor/github.com/go-chi/chi/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: go - -go: - - 1.10.x - - 1.11.x - -script: - - go get -d -t ./... - - go vet ./... - - go test ./... - - > - go_version=$(go version); - if [ ${go_version:13:4} = "1.11" ]; then - go get -u golang.org/x/tools/cmd/goimports; - goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || :; - fi - diff --git a/vendor/github.com/go-chi/chi/CHANGELOG.md b/vendor/github.com/go-chi/chi/CHANGELOG.md deleted file mode 100644 index d03e40c..0000000 --- a/vendor/github.com/go-chi/chi/CHANGELOG.md +++ /dev/null @@ -1,139 +0,0 @@ -# Changelog - -## v4.0.0 (2019-01-10) - -- chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8 -- router: respond with 404 on router with no routes (#362) -- router: additional check to ensure wildcard is at the end of a url pattern (#333) -- middleware: deprecate use of http.CloseNotifier (#347) -- middleware: fix RedirectSlashes to include query params on redirect (#334) -- History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0 - - -## v3.3.4 (2019-01-07) - -- Minor middleware improvements. No changes to core library/router. Moving v3 into its -- own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11 -- History of changes: see https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4 - - -## v3.3.3 (2018-08-27) - -- Minor release -- See https://github.com/go-chi/chi/compare/v3.3.2...v3.3.3 - - -## v3.3.2 (2017-12-22) - -- Support to route trailing slashes on mounted sub-routers (#281) -- middleware: new `ContentCharset` to check matching charsets. Thank you - @csucu for your community contribution! - - -## v3.3.1 (2017-11-20) - -- middleware: new `AllowContentType` handler for explicit whitelist of accepted request Content-Types -- middleware: new `SetHeader` handler for short-hand middleware to set a response header key/value -- Minor bug fixes - - -## v3.3.0 (2017-10-10) - -- New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage -- Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function - - -## v3.2.1 (2017-08-31) - -- Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface - and `Mux`. Match searches the mux's routing tree for a handler that matches the method/path -- Add new `RouteMethod` to `*Context` -- Add new `Routes` pointer to `*Context` -- Add new `middleware.GetHead` to route missing HEAD requests to GET handler -- Updated benchmarks (see README) - - -## v3.1.5 (2017-08-02) - -- Setup golint and go vet for the project -- As per golint, we've redefined `func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler` - to `func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler` - - -## v3.1.0 (2017-07-10) - -- Fix a few minor issues after v3 release -- Move `docgen` sub-pkg to https://github.com/go-chi/docgen -- Move `render` sub-pkg to https://github.com/go-chi/render -- Add new `URLFormat` handler to chi/middleware sub-pkg to make working with url mime - suffixes easier, ie. parsing `/articles/1.json` and `/articles/1.xml`. See comments in - https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage. - - -## v3.0.0 (2017-06-21) - -- Major update to chi library with many exciting updates, but also some *breaking changes* -- URL parameter syntax changed from `/:id` to `/{id}` for even more flexible routing, such as - `/articles/{month}-{day}-{year}-{slug}`, `/articles/{id}`, and `/articles/{id}.{ext}` on the - same router -- Support for regexp for routing patterns, in the form of `/{paramKey:regExp}` for example: - `r.Get("/articles/{name:[a-z]+}", h)` and `chi.URLParam(r, "name")` -- Add `Method` and `MethodFunc` to `chi.Router` to allow routing definitions such as - `r.Method("GET", "/", h)` which provides a cleaner interface for custom handlers like - in `_examples/custom-handler` -- Deprecating `mux#FileServer` helper function. Instead, we encourage users to create their - own using file handler with the stdlib, see `_examples/fileserver` for an example -- Add support for LINK/UNLINK http methods via `r.Method()` and `r.MethodFunc()` -- Moved the chi project to its own organization, to allow chi-related community packages to - be easily discovered and supported, at: https://github.com/go-chi -- *NOTE:* please update your import paths to `"github.com/go-chi/chi"` -- *NOTE:* chi v2 is still available at https://github.com/go-chi/chi/tree/v2 - - -## v2.1.0 (2017-03-30) - -- Minor improvements and update to the chi core library -- Introduced a brand new `chi/render` sub-package to complete the story of building - APIs to offer a pattern for managing well-defined request / response payloads. Please - check out the updated `_examples/rest` example for how it works. -- Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface - - -## v2.0.0 (2017-01-06) - -- After many months of v2 being in an RC state with many companies and users running it in - production, the inclusion of some improvements to the middlewares, we are very pleased to - announce v2.0.0 of chi. - - -## v2.0.0-rc1 (2016-07-26) - -- Huge update! chi v2 is a large refactor targetting Go 1.7+. As of Go 1.7, the popular - community `"net/context"` package has been included in the standard library as `"context"` and - utilized by `"net/http"` and `http.Request` to managing deadlines, cancelation signals and other - request-scoped values. We're very excited about the new context addition and are proud to - introduce chi v2, a minimal and powerful routing package for building large HTTP services, - with zero external dependencies. Chi focuses on idiomatic design and encourages the use of - stdlib HTTP handlers and middlwares. -- chi v2 deprecates its `chi.Handler` interface and requires `http.Handler` or `http.HandlerFunc` -- chi v2 stores URL routing parameters and patterns in the standard request context: `r.Context()` -- chi v2 lower-level routing context is accessible by `chi.RouteContext(r.Context()) *chi.Context`, - which provides direct access to URL routing parameters, the routing path and the matching - routing patterns. -- Users upgrading from chi v1 to v2, need to: - 1. Update the old chi.Handler signature, `func(ctx context.Context, w http.ResponseWriter, r *http.Request)` to - the standard http.Handler: `func(w http.ResponseWriter, r *http.Request)` - 2. Use `chi.URLParam(r *http.Request, paramKey string) string` - or `URLParamFromCtx(ctx context.Context, paramKey string) string` to access a url parameter value - - -## v1.0.0 (2016-07-01) - -- Released chi v1 stable https://github.com/go-chi/chi/tree/v1.0.0 for Go 1.6 and older. - - -## v0.9.0 (2016-03-31) - -- Reuse context objects via sync.Pool for zero-allocation routing [#33](https://github.com/go-chi/chi/pull/33) -- BREAKING NOTE: due to subtle API changes, previously `chi.URLParams(ctx)["id"]` used to access url parameters - has changed to: `chi.URLParam(ctx, "id")` diff --git a/vendor/github.com/go-chi/chi/CONTRIBUTING.md b/vendor/github.com/go-chi/chi/CONTRIBUTING.md deleted file mode 100644 index c0ac2df..0000000 --- a/vendor/github.com/go-chi/chi/CONTRIBUTING.md +++ /dev/null @@ -1,31 +0,0 @@ -# Contributing - -## Prerequisites - -1. [Install Go][go-install]. -2. Download the sources and switch the working directory: - - ```bash - go get -u -d github.com/go-chi/chi - cd $GOPATH/src/github.com/go-chi/chi - ``` - -## Submitting a Pull Request - -A typical workflow is: - -1. [Fork the repository.][fork] [This tip maybe also helpful.][go-fork-tip] -2. [Create a topic branch.][branch] -3. Add tests for your change. -4. Run `go test`. If your tests pass, return to the step 3. -5. Implement the change and ensure the steps from the previous step pass. -6. Run `goimports -w .`, to ensure the new code conforms to Go formatting guideline. -7. [Add, commit and push your changes.][git-help] -8. [Submit a pull request.][pull-req] - -[go-install]: https://golang.org/doc/install -[go-fork-tip]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html -[fork]: https://help.github.com/articles/fork-a-repo -[branch]: http://learn.github.com/p/branching.html -[git-help]: https://guides.github.com -[pull-req]: https://help.github.com/articles/using-pull-requests diff --git a/vendor/github.com/go-chi/chi/LICENSE b/vendor/github.com/go-chi/chi/LICENSE deleted file mode 100644 index d99f02f..0000000 --- a/vendor/github.com/go-chi/chi/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc. - -MIT License - -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. diff --git a/vendor/github.com/go-chi/chi/README.md b/vendor/github.com/go-chi/chi/README.md deleted file mode 100644 index d36d4db..0000000 --- a/vendor/github.com/go-chi/chi/README.md +++ /dev/null @@ -1,438 +0,0 @@ -# chi - - -[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis] - -`chi` is a lightweight, idiomatic and composable router for building Go HTTP services. It's -especially good at helping you write large REST API services that are kept maintainable as your -project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to -handle signaling, cancelation and request-scoped values across a handler chain. - -The focus of the project has been to seek out an elegant and comfortable design for writing -REST API servers, written during the development of the Pressly API service that powers our -public API service, which in turn powers all of our client-side applications. - -The key considerations of chi's design are: project structure, maintainability, standard http -handlers (stdlib-only), developer productivity, and deconstructing a large system into many small -parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also -included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too! - -## Install - -`go get -u github.com/go-chi/chi` - - -## Features - -* **Lightweight** - cloc'd in ~1000 LOC for the chi router -* **Fast** - yes, see [benchmarks](#benchmarks) -* **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http` -* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and subrouter mounting -* **Context control** - built on new `context` package, providing value chaining, cancelations and timeouts -* **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91)) -* **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown -* **No external dependencies** - plain ol' Go stdlib + net/http - - -## Examples - -See [_examples/](https://github.com/go-chi/chi/blob/master/_examples/) for a variety of examples. - - -**As easy as:** - -```go -package main - -import ( - "net/http" - "github.com/go-chi/chi" -) - -func main() { - r := chi.NewRouter() - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("welcome")) - }) - http.ListenAndServe(":3000", r) -} -``` - -**REST Preview:** - -Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs -in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in -Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)). - -I highly recommend reading the source of the [examples](https://github.com/go-chi/chi/blob/master/_examples/) listed -above, they will show you all the features of chi and serve as a good form of documentation. - -```go -import ( - //... - "context" - "github.com/go-chi/chi" - "github.com/go-chi/chi/middleware" -) - -func main() { - r := chi.NewRouter() - - // A good base middleware stack - r.Use(middleware.RequestID) - r.Use(middleware.RealIP) - r.Use(middleware.Logger) - r.Use(middleware.Recoverer) - - // Set a timeout value on the request context (ctx), that will signal - // through ctx.Done() that the request has timed out and further - // processing should be stopped. - r.Use(middleware.Timeout(60 * time.Second)) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hi")) - }) - - // RESTy routes for "articles" resource - r.Route("/articles", func(r chi.Router) { - r.With(paginate).Get("/", listArticles) // GET /articles - r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017 - - r.Post("/", createArticle) // POST /articles - r.Get("/search", searchArticles) // GET /articles/search - - // Regexp url parameters: - r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto - - // Subrouters: - r.Route("/{articleID}", func(r chi.Router) { - r.Use(ArticleCtx) - r.Get("/", getArticle) // GET /articles/123 - r.Put("/", updateArticle) // PUT /articles/123 - r.Delete("/", deleteArticle) // DELETE /articles/123 - }) - }) - - // Mount the admin sub-router - r.Mount("/admin", adminRouter()) - - http.ListenAndServe(":3333", r) -} - -func ArticleCtx(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - articleID := chi.URLParam(r, "articleID") - article, err := dbGetArticle(articleID) - if err != nil { - http.Error(w, http.StatusText(404), 404) - return - } - ctx := context.WithValue(r.Context(), "article", article) - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} - -func getArticle(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - article, ok := ctx.Value("article").(*Article) - if !ok { - http.Error(w, http.StatusText(422), 422) - return - } - w.Write([]byte(fmt.Sprintf("title:%s", article.Title))) -} - -// A completely separate router for administrator routes -func adminRouter() http.Handler { - r := chi.NewRouter() - r.Use(AdminOnly) - r.Get("/", adminIndex) - r.Get("/accounts", adminListAccounts) - return r -} - -func AdminOnly(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - perm, ok := ctx.Value("acl.permission").(YourPermissionType) - if !ok || !perm.IsAdmin() { - http.Error(w, http.StatusText(403), 403) - return - } - next.ServeHTTP(w, r) - }) -} -``` - - -## Router design - -chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree). -The router is fully compatible with `net/http`. - -Built on top of the tree is the `Router` interface: - -```go -// Router consisting of the core routing methods used by chi's Mux, -// using only the standard net/http. -type Router interface { - http.Handler - Routes - - // Use appends one of more middlewares onto the Router stack. - Use(middlewares ...func(http.Handler) http.Handler) - - // With adds inline middlewares for an endpoint handler. - With(middlewares ...func(http.Handler) http.Handler) Router - - // Group adds a new inline-Router along the current routing - // path, with a fresh middleware stack for the inline-Router. - Group(fn func(r Router)) Router - - // Route mounts a sub-Router along a `pattern`` string. - Route(pattern string, fn func(r Router)) Router - - // Mount attaches another http.Handler along ./pattern/* - Mount(pattern string, h http.Handler) - - // Handle and HandleFunc adds routes for `pattern` that matches - // all HTTP methods. - Handle(pattern string, h http.Handler) - HandleFunc(pattern string, h http.HandlerFunc) - - // Method and MethodFunc adds routes for `pattern` that matches - // the `method` HTTP method. - Method(method, pattern string, h http.Handler) - MethodFunc(method, pattern string, h http.HandlerFunc) - - // HTTP-method routing along `pattern` - Connect(pattern string, h http.HandlerFunc) - Delete(pattern string, h http.HandlerFunc) - Get(pattern string, h http.HandlerFunc) - Head(pattern string, h http.HandlerFunc) - Options(pattern string, h http.HandlerFunc) - Patch(pattern string, h http.HandlerFunc) - Post(pattern string, h http.HandlerFunc) - Put(pattern string, h http.HandlerFunc) - Trace(pattern string, h http.HandlerFunc) - - // NotFound defines a handler to respond whenever a route could - // not be found. - NotFound(h http.HandlerFunc) - - // MethodNotAllowed defines a handler to respond whenever a method is - // not allowed. - MethodNotAllowed(h http.HandlerFunc) -} - -// Routes interface adds two methods for router traversal, which is also -// used by the github.com/go-chi/docgen package to generate documentation for Routers. -type Routes interface { - // Routes returns the routing tree in an easily traversable structure. - Routes() []Route - - // Middlewares returns the list of middlewares in use by the router. - Middlewares() Middlewares - - // Match searches the routing tree for a handler that matches - // the method/path - similar to routing a http request, but without - // executing the handler thereafter. - Match(rctx *Context, method, path string) bool -} -``` - -Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern -supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters -can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters -and `chi.URLParam(r, "*")` for a wildcard parameter. - - -### Middleware handlers - -chi's middlewares are just stdlib net/http middleware handlers. There is nothing special -about them, which means the router and all the tooling is designed to be compatible and -friendly with any middleware in the community. This offers much better extensibility and reuse -of packages and is at the heart of chi's purpose. - -Here is an example of a standard net/http middleware handler using the new request context -available in Go. This middleware sets a hypothetical user identifier on the request -context and calls the next handler in the chain. - -```go -// HTTP middleware setting a value on the request context -func MyMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), "user", "123") - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} -``` - - -### Request handlers - -chi uses standard net/http request handlers. This little snippet is an example of a http.Handler -func that reads a user identifier from the request context - hypothetically, identifying -the user sending an authenticated request, validated+set by a previous middleware handler. - -```go -// HTTP handler accessing data from the request context. -func MyRequestHandler(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value("user").(string) - w.Write([]byte(fmt.Sprintf("hi %s", user))) -} -``` - - -### URL parameters - -chi's router parses and stores URL parameters right onto the request context. Here is -an example of how to access URL params in your net/http handlers. And of course, middlewares -are able to access the same information. - -```go -// HTTP handler accessing the url routing parameters. -func MyRequestHandler(w http.ResponseWriter, r *http.Request) { - userID := chi.URLParam(r, "userID") // from a route like /users/{userID} - - ctx := r.Context() - key := ctx.Value("key").(string) - - w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key))) -} -``` - - -## Middlewares - -chi comes equipped with an optional `middleware` package, providing a suite of standard -`net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible -with `net/http` can be used with chi's mux. - -### Core middlewares - ------------------------------------------------------------------------------------------------------------ -| chi/middleware Handler | description | -|:----------------------|:--------------------------------------------------------------------------------- -| AllowContentType | Explicit whitelist of accepted request Content-Types | -| Compress | Gzip compression for clients that accept compressed responses | -| GetHead | Automatically route undefined HEAD requests to GET handlers | -| Heartbeat | Monitoring endpoint to check the servers pulse | -| Logger | Logs the start and end of each request with the elapsed processing time | -| NoCache | Sets response headers to prevent clients from caching | -| Profiler | Easily attach net/http/pprof to your routers | -| RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP | -| Recoverer | Gracefully absorb panics and prints the stack trace | -| RequestID | Injects a request ID into the context of each request | -| RedirectSlashes | Redirect slashes on routing paths | -| SetHeader | Short-hand middleware to set a response header key/value | -| StripSlashes | Strip slashes on routing paths | -| Throttle | Puts a ceiling on the number of concurrent requests | -| Timeout | Signals to the request context when the timeout deadline is reached | -| URLFormat | Parse extension from url and put it on request context | -| WithValue | Short-hand middleware to set a key/value on the request context | ------------------------------------------------------------------------------------------------------------ - -### Auxiliary middlewares & packages - -Please see https://github.com/go-chi for additional packages. - --------------------------------------------------------------------------------------------------------------------- -| package | description | -|:---------------------------------------------------|:------------------------------------------------------------- -| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) | -| [docgen](https://github.com/go-chi/docgen) | Print chi.Router routes at runtime | -| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication | -| [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing | -| [httpcoala](https://github.com/go-chi/httpcoala) | HTTP request coalescer | -| [chi-authz](https://github.com/casbin/chi-authz) | Request ACL via https://github.com/hsluoyz/casbin | -| [phi](https://github.com/fate-lovely/phi) | Port chi to [fasthttp](https://github.com/valyala/fasthttp) | --------------------------------------------------------------------------------------------------------------------- - -please [submit a PR](./CONTRIBUTING.md) if you'd like to include a link to a chi-compatible middleware - - -## context? - -`context` is a tiny pkg that provides simple interface to signal context across call stacks -and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani) -and is available in stdlib since go1.7. - -Learn more at https://blog.golang.org/context - -and.. -* Docs: https://golang.org/pkg/context -* Source: https://github.com/golang/go/tree/master/src/context - - -## Benchmarks - -The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark - -Results as of Jan 9, 2019 with Go 1.11.4 on Linux X1 Carbon laptop - -```shell -BenchmarkChi_Param 3000000 475 ns/op 432 B/op 3 allocs/op -BenchmarkChi_Param5 2000000 696 ns/op 432 B/op 3 allocs/op -BenchmarkChi_Param20 1000000 1275 ns/op 432 B/op 3 allocs/op -BenchmarkChi_ParamWrite 3000000 505 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GithubStatic 3000000 508 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GithubParam 2000000 669 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GithubAll 10000 134627 ns/op 87699 B/op 609 allocs/op -BenchmarkChi_GPlusStatic 3000000 402 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GPlusParam 3000000 500 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GPlus2Params 3000000 586 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GPlusAll 200000 7237 ns/op 5616 B/op 39 allocs/op -BenchmarkChi_ParseStatic 3000000 408 ns/op 432 B/op 3 allocs/op -BenchmarkChi_ParseParam 3000000 488 ns/op 432 B/op 3 allocs/op -BenchmarkChi_Parse2Params 3000000 551 ns/op 432 B/op 3 allocs/op -BenchmarkChi_ParseAll 100000 13508 ns/op 11232 B/op 78 allocs/op -BenchmarkChi_StaticAll 20000 81933 ns/op 67826 B/op 471 allocs/op -``` - -Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc - -NOTE: the allocs in the benchmark above are from the calls to http.Request's -`WithContext(context.Context)` method that clones the http.Request, sets the `Context()` -on the duplicated (alloc'd) request and returns it the new request object. This is just -how setting context on a request in Go works. - - -## Credits - -* Carl Jackson for https://github.com/zenazn/goji - * Parts of chi's thinking comes from goji, and chi's middleware package - sources from goji. -* Armon Dadgar for https://github.com/armon/go-radix -* Contributions: [@VojtechVitek](https://github.com/VojtechVitek) - -We'll be more than happy to see [your contributions](./CONTRIBUTING.md)! - - -## Beyond REST - -chi is just a http router that lets you decompose request handling into many smaller layers. -Many companies including Pressly.com (of course) use chi to write REST services for their public -APIs. But, REST is just a convention for managing state via HTTP, and there's a lot of other pieces -required to write a complete client-server system or network of microservices. - -Looking ahead beyond REST, I also recommend some newer works in the field coming from -[gRPC](https://github.com/grpc/grpc-go), [NATS](https://nats.io), [go-kit](https://github.com/go-kit/kit) -and even [graphql](https://github.com/graphql-go/graphql). They're all pretty cool with their -own unique approaches and benefits. Specifically, I'd look at gRPC since it makes client-server -communication feel like a single program on a single computer, no need to hand-write a client library -and the request/response payloads are typed contracts. NATS is pretty amazing too as a super -fast and lightweight pub-sub transport that can speak protobufs, with nice service discovery - -an excellent combination with gRPC. - - -## License - -Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka) - -Licensed under [MIT License](./LICENSE) - -[GoDoc]: https://godoc.org/github.com/go-chi/chi -[GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg -[Travis]: https://travis-ci.org/go-chi/chi -[Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master diff --git a/vendor/github.com/go-chi/chi/chain.go b/vendor/github.com/go-chi/chi/chain.go deleted file mode 100644 index 88e6846..0000000 --- a/vendor/github.com/go-chi/chi/chain.go +++ /dev/null @@ -1,49 +0,0 @@ -package chi - -import "net/http" - -// Chain returns a Middlewares type from a slice of middleware handlers. -func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares { - return Middlewares(middlewares) -} - -// Handler builds and returns a http.Handler from the chain of middlewares, -// with `h http.Handler` as the final handler. -func (mws Middlewares) Handler(h http.Handler) http.Handler { - return &ChainHandler{mws, h, chain(mws, h)} -} - -// HandlerFunc builds and returns a http.Handler from the chain of middlewares, -// with `h http.Handler` as the final handler. -func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler { - return &ChainHandler{mws, h, chain(mws, h)} -} - -// ChainHandler is a http.Handler with support for handler composition and -// execution. -type ChainHandler struct { - Middlewares Middlewares - Endpoint http.Handler - chain http.Handler -} - -func (c *ChainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - c.chain.ServeHTTP(w, r) -} - -// chain builds a http.Handler composed of an inline middleware stack and endpoint -// handler in the order they are passed. -func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler { - // Return ahead of time if there aren't any middlewares for the chain - if len(middlewares) == 0 { - return endpoint - } - - // Wrap the end handler with the middleware chain - h := middlewares[len(middlewares)-1](endpoint) - for i := len(middlewares) - 2; i >= 0; i-- { - h = middlewares[i](h) - } - - return h -} diff --git a/vendor/github.com/go-chi/chi/chi.go b/vendor/github.com/go-chi/chi/chi.go deleted file mode 100644 index 9962229..0000000 --- a/vendor/github.com/go-chi/chi/chi.go +++ /dev/null @@ -1,134 +0,0 @@ -// -// Package chi is a small, idiomatic and composable router for building HTTP services. -// -// chi requires Go 1.7 or newer. -// -// Example: -// package main -// -// import ( -// "net/http" -// -// "github.com/go-chi/chi" -// "github.com/go-chi/chi/middleware" -// ) -// -// func main() { -// r := chi.NewRouter() -// r.Use(middleware.Logger) -// r.Use(middleware.Recoverer) -// -// r.Get("/", func(w http.ResponseWriter, r *http.Request) { -// w.Write([]byte("root.")) -// }) -// -// http.ListenAndServe(":3333", r) -// } -// -// See github.com/go-chi/chi/_examples/ for more in-depth examples. -// -// URL patterns allow for easy matching of path components in HTTP -// requests. The matching components can then be accessed using -// chi.URLParam(). All patterns must begin with a slash. -// -// A simple named placeholder {name} matches any sequence of characters -// up to the next / or the end of the URL. Trailing slashes on paths must -// be handled explicitly. -// -// A placeholder with a name followed by a colon allows a regular -// expression match, for example {number:\\d+}. The regular expression -// syntax is Go's normal regexp RE2 syntax, except that regular expressions -// including { or } are not supported, and / will never be -// matched. An anonymous regexp pattern is allowed, using an empty string -// before the colon in the placeholder, such as {:\\d+} -// -// The special placeholder of asterisk matches the rest of the requested -// URL. Any trailing characters in the pattern are ignored. This is the only -// placeholder which will match / characters. -// -// Examples: -// "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/" -// "/user/{name}/info" matches "/user/jsmith/info" -// "/page/*" matches "/page/intro/latest" -// "/page/*/index" also matches "/page/intro/latest" -// "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01" -// -package chi - -import "net/http" - -// NewRouter returns a new Mux object that implements the Router interface. -func NewRouter() *Mux { - return NewMux() -} - -// Router consisting of the core routing methods used by chi's Mux, -// using only the standard net/http. -type Router interface { - http.Handler - Routes - - // Use appends one of more middlewares onto the Router stack. - Use(middlewares ...func(http.Handler) http.Handler) - - // With adds inline middlewares for an endpoint handler. - With(middlewares ...func(http.Handler) http.Handler) Router - - // Group adds a new inline-Router along the current routing - // path, with a fresh middleware stack for the inline-Router. - Group(fn func(r Router)) Router - - // Route mounts a sub-Router along a `pattern`` string. - Route(pattern string, fn func(r Router)) Router - - // Mount attaches another http.Handler along ./pattern/* - Mount(pattern string, h http.Handler) - - // Handle and HandleFunc adds routes for `pattern` that matches - // all HTTP methods. - Handle(pattern string, h http.Handler) - HandleFunc(pattern string, h http.HandlerFunc) - - // Method and MethodFunc adds routes for `pattern` that matches - // the `method` HTTP method. - Method(method, pattern string, h http.Handler) - MethodFunc(method, pattern string, h http.HandlerFunc) - - // HTTP-method routing along `pattern` - Connect(pattern string, h http.HandlerFunc) - Delete(pattern string, h http.HandlerFunc) - Get(pattern string, h http.HandlerFunc) - Head(pattern string, h http.HandlerFunc) - Options(pattern string, h http.HandlerFunc) - Patch(pattern string, h http.HandlerFunc) - Post(pattern string, h http.HandlerFunc) - Put(pattern string, h http.HandlerFunc) - Trace(pattern string, h http.HandlerFunc) - - // NotFound defines a handler to respond whenever a route could - // not be found. - NotFound(h http.HandlerFunc) - - // MethodNotAllowed defines a handler to respond whenever a method is - // not allowed. - MethodNotAllowed(h http.HandlerFunc) -} - -// Routes interface adds two methods for router traversal, which is also -// used by the `docgen` subpackage to generation documentation for Routers. -type Routes interface { - // Routes returns the routing tree in an easily traversable structure. - Routes() []Route - - // Middlewares returns the list of middlewares in use by the router. - Middlewares() Middlewares - - // Match searches the routing tree for a handler that matches - // the method/path - similar to routing a http request, but without - // executing the handler thereafter. - Match(rctx *Context, method, path string) bool -} - -// Middlewares type is a slice of standard middleware handlers with methods -// to compose middleware chains and http.Handler's. -type Middlewares []func(http.Handler) http.Handler diff --git a/vendor/github.com/go-chi/chi/context.go b/vendor/github.com/go-chi/chi/context.go deleted file mode 100644 index 229c9cb..0000000 --- a/vendor/github.com/go-chi/chi/context.go +++ /dev/null @@ -1,161 +0,0 @@ -package chi - -import ( - "context" - "net" - "net/http" - "strings" -) - -var ( - // RouteCtxKey is the context.Context key to store the request context. - RouteCtxKey = &contextKey{"RouteContext"} -) - -// Context is the default routing context set on the root node of a -// request context to track route patterns, URL parameters and -// an optional routing path. -type Context struct { - Routes Routes - - // Routing path/method override used during the route search. - // See Mux#routeHTTP method. - RoutePath string - RouteMethod string - - // Routing pattern stack throughout the lifecycle of the request, - // across all connected routers. It is a record of all matching - // patterns across a stack of sub-routers. - RoutePatterns []string - - // URLParams are the stack of routeParams captured during the - // routing lifecycle across a stack of sub-routers. - URLParams RouteParams - - // The endpoint routing pattern that matched the request URI path - // or `RoutePath` of the current sub-router. This value will update - // during the lifecycle of a request passing through a stack of - // sub-routers. - routePattern string - - // Route parameters matched for the current sub-router. It is - // intentionally unexported so it cant be tampered. - routeParams RouteParams - - // methodNotAllowed hint - methodNotAllowed bool -} - -// NewRouteContext returns a new routing Context object. -func NewRouteContext() *Context { - return &Context{} -} - -// Reset a routing context to its initial state. -func (x *Context) Reset() { - x.Routes = nil - x.RoutePath = "" - x.RouteMethod = "" - x.RoutePatterns = x.RoutePatterns[:0] - x.URLParams.Keys = x.URLParams.Keys[:0] - x.URLParams.Values = x.URLParams.Values[:0] - - x.routePattern = "" - x.routeParams.Keys = x.routeParams.Keys[:0] - x.routeParams.Values = x.routeParams.Values[:0] - x.methodNotAllowed = false -} - -// URLParam returns the corresponding URL parameter value from the request -// routing context. -func (x *Context) URLParam(key string) string { - for k := len(x.URLParams.Keys) - 1; k >= 0; k-- { - if x.URLParams.Keys[k] == key { - return x.URLParams.Values[k] - } - } - return "" -} - -// RoutePattern builds the routing pattern string for the particular -// request, at the particular point during routing. This means, the value -// will change throughout the execution of a request in a router. That is -// why its advised to only use this value after calling the next handler. -// -// For example, -// -// func Instrument(next http.Handler) http.Handler { -// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// next.ServeHTTP(w, r) -// routePattern := chi.RouteContext(r.Context()).RoutePattern() -// measure(w, r, routePattern) -// }) -// } -func (x *Context) RoutePattern() string { - routePattern := strings.Join(x.RoutePatterns, "") - return strings.Replace(routePattern, "/*/", "/", -1) -} - -// RouteContext returns chi's routing Context object from a -// http.Request Context. -func RouteContext(ctx context.Context) *Context { - return ctx.Value(RouteCtxKey).(*Context) -} - -// URLParam returns the url parameter from a http.Request object. -func URLParam(r *http.Request, key string) string { - if rctx := RouteContext(r.Context()); rctx != nil { - return rctx.URLParam(key) - } - return "" -} - -// URLParamFromCtx returns the url parameter from a http.Request Context. -func URLParamFromCtx(ctx context.Context, key string) string { - if rctx := RouteContext(ctx); rctx != nil { - return rctx.URLParam(key) - } - return "" -} - -// RouteParams is a structure to track URL routing parameters efficiently. -type RouteParams struct { - Keys, Values []string -} - -// Add will append a URL parameter to the end of the route param -func (s *RouteParams) Add(key, value string) { - (*s).Keys = append((*s).Keys, key) - (*s).Values = append((*s).Values, value) -} - -// ServerBaseContext wraps an http.Handler to set the request context to the -// `baseCtx`. -func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler { - fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - baseCtx := baseCtx - - // Copy over default net/http server context keys - if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok { - baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v) - } - if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok { - baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v) - } - - h.ServeHTTP(w, r.WithContext(baseCtx)) - }) - return fn -} - -// contextKey is a value for use with context.WithValue. It's used as -// a pointer so it fits in an interface{} without allocation. This technique -// for defining context keys was copied from Go 1.7's new use of context in net/http. -type contextKey struct { - name string -} - -func (k *contextKey) String() string { - return "chi context value " + k.name -} diff --git a/vendor/github.com/go-chi/chi/mux.go b/vendor/github.com/go-chi/chi/mux.go deleted file mode 100644 index e553287..0000000 --- a/vendor/github.com/go-chi/chi/mux.go +++ /dev/null @@ -1,460 +0,0 @@ -package chi - -import ( - "context" - "fmt" - "net/http" - "strings" - "sync" -) - -var _ Router = &Mux{} - -// Mux is a simple HTTP route multiplexer that parses a request path, -// records any URL params, and executes an end handler. It implements -// the http.Handler interface and is friendly with the standard library. -// -// Mux is designed to be fast, minimal and offer a powerful API for building -// modular and composable HTTP services with a large set of handlers. It's -// particularly useful for writing large REST API services that break a handler -// into many smaller parts composed of middlewares and end handlers. -type Mux struct { - // The radix trie router - tree *node - - // The middleware stack - middlewares []func(http.Handler) http.Handler - - // Controls the behaviour of middleware chain generation when a mux - // is registered as an inline group inside another mux. - inline bool - parent *Mux - - // The computed mux handler made of the chained middleware stack and - // the tree router - handler http.Handler - - // Routing context pool - pool *sync.Pool - - // Custom route not found handler - notFoundHandler http.HandlerFunc - - // Custom method not allowed handler - methodNotAllowedHandler http.HandlerFunc -} - -// NewMux returns a newly initialized Mux object that implements the Router -// interface. -func NewMux() *Mux { - mux := &Mux{tree: &node{}, pool: &sync.Pool{}} - mux.pool.New = func() interface{} { - return NewRouteContext() - } - return mux -} - -// ServeHTTP is the single method of the http.Handler interface that makes -// Mux interoperable with the standard library. It uses a sync.Pool to get and -// reuse routing contexts for each request. -func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // Ensure the mux has some routes defined on the mux - if mx.handler == nil { - mx.NotFoundHandler().ServeHTTP(w, r) - return - } - - // Check if a routing context already exists from a parent router. - rctx, _ := r.Context().Value(RouteCtxKey).(*Context) - if rctx != nil { - mx.handler.ServeHTTP(w, r) - return - } - - // Fetch a RouteContext object from the sync pool, and call the computed - // mx.handler that is comprised of mx.middlewares + mx.routeHTTP. - // Once the request is finished, reset the routing context and put it back - // into the pool for reuse from another request. - rctx = mx.pool.Get().(*Context) - rctx.Reset() - rctx.Routes = mx - r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx)) - mx.handler.ServeHTTP(w, r) - mx.pool.Put(rctx) -} - -// Use appends a middleware handler to the Mux middleware stack. -// -// The middleware stack for any Mux will execute before searching for a matching -// route to a specific handler, which provides opportunity to respond early, -// change the course of the request execution, or set request-scoped values for -// the next http.Handler. -func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) { - if mx.handler != nil { - panic("chi: all middlewares must be defined before routes on a mux") - } - mx.middlewares = append(mx.middlewares, middlewares...) -} - -// Handle adds the route `pattern` that matches any http method to -// execute the `handler` http.Handler. -func (mx *Mux) Handle(pattern string, handler http.Handler) { - mx.handle(mALL, pattern, handler) -} - -// HandleFunc adds the route `pattern` that matches any http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mALL, pattern, handlerFn) -} - -// Method adds the route `pattern` that matches `method` http method to -// execute the `handler` http.Handler. -func (mx *Mux) Method(method, pattern string, handler http.Handler) { - m, ok := methodMap[strings.ToUpper(method)] - if !ok { - panic(fmt.Sprintf("chi: '%s' http method is not supported.", method)) - } - mx.handle(m, pattern, handler) -} - -// MethodFunc adds the route `pattern` that matches `method` http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) MethodFunc(method, pattern string, handlerFn http.HandlerFunc) { - mx.Method(method, pattern, handlerFn) -} - -// Connect adds the route `pattern` that matches a CONNECT http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Connect(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mCONNECT, pattern, handlerFn) -} - -// Delete adds the route `pattern` that matches a DELETE http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Delete(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mDELETE, pattern, handlerFn) -} - -// Get adds the route `pattern` that matches a GET http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Get(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mGET, pattern, handlerFn) -} - -// Head adds the route `pattern` that matches a HEAD http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Head(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mHEAD, pattern, handlerFn) -} - -// Options adds the route `pattern` that matches a OPTIONS http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Options(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mOPTIONS, pattern, handlerFn) -} - -// Patch adds the route `pattern` that matches a PATCH http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Patch(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mPATCH, pattern, handlerFn) -} - -// Post adds the route `pattern` that matches a POST http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Post(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mPOST, pattern, handlerFn) -} - -// Put adds the route `pattern` that matches a PUT http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mPUT, pattern, handlerFn) -} - -// Trace adds the route `pattern` that matches a TRACE http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mTRACE, pattern, handlerFn) -} - -// NotFound sets a custom http.HandlerFunc for routing paths that could -// not be found. The default 404 handler is `http.NotFound`. -func (mx *Mux) NotFound(handlerFn http.HandlerFunc) { - // Build NotFound handler chain - m := mx - hFn := handlerFn - if mx.inline && mx.parent != nil { - m = mx.parent - hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP - } - - // Update the notFoundHandler from this point forward - m.notFoundHandler = hFn - m.updateSubRoutes(func(subMux *Mux) { - if subMux.notFoundHandler == nil { - subMux.NotFound(hFn) - } - }) -} - -// MethodNotAllowed sets a custom http.HandlerFunc for routing paths where the -// method is unresolved. The default handler returns a 405 with an empty body. -func (mx *Mux) MethodNotAllowed(handlerFn http.HandlerFunc) { - // Build MethodNotAllowed handler chain - m := mx - hFn := handlerFn - if mx.inline && mx.parent != nil { - m = mx.parent - hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP - } - - // Update the methodNotAllowedHandler from this point forward - m.methodNotAllowedHandler = hFn - m.updateSubRoutes(func(subMux *Mux) { - if subMux.methodNotAllowedHandler == nil { - subMux.MethodNotAllowed(hFn) - } - }) -} - -// With adds inline middlewares for an endpoint handler. -func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router { - // Similarly as in handle(), we must build the mux handler once further - // middleware registration isn't allowed for this stack, like now. - if !mx.inline && mx.handler == nil { - mx.buildRouteHandler() - } - - // Copy middlewares from parent inline muxs - var mws Middlewares - if mx.inline { - mws = make(Middlewares, len(mx.middlewares)) - copy(mws, mx.middlewares) - } - mws = append(mws, middlewares...) - - im := &Mux{pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws} - - return im -} - -// Group creates a new inline-Mux with a fresh middleware stack. It's useful -// for a group of handlers along the same routing path that use an additional -// set of middlewares. See _examples/. -func (mx *Mux) Group(fn func(r Router)) Router { - im := mx.With().(*Mux) - if fn != nil { - fn(im) - } - return im -} - -// Route creates a new Mux with a fresh middleware stack and mounts it -// along the `pattern` as a subrouter. Effectively, this is a short-hand -// call to Mount. See _examples/. -func (mx *Mux) Route(pattern string, fn func(r Router)) Router { - subRouter := NewRouter() - if fn != nil { - fn(subRouter) - } - mx.Mount(pattern, subRouter) - return subRouter -} - -// Mount attaches another http.Handler or chi Router as a subrouter along a routing -// path. It's very useful to split up a large API as many independent routers and -// compose them as a single service using Mount. See _examples/. -// -// Note that Mount() simply sets a wildcard along the `pattern` that will continue -// routing at the `handler`, which in most cases is another chi.Router. As a result, -// if you define two Mount() routes on the exact same pattern the mount will panic. -func (mx *Mux) Mount(pattern string, handler http.Handler) { - // Provide runtime safety for ensuring a pattern isn't mounted on an existing - // routing pattern. - if mx.tree.findPattern(pattern+"*") || mx.tree.findPattern(pattern+"/*") { - panic(fmt.Sprintf("chi: attempting to Mount() a handler on an existing path, '%s'", pattern)) - } - - // Assign sub-Router's with the parent not found & method not allowed handler if not specified. - subr, ok := handler.(*Mux) - if ok && subr.notFoundHandler == nil && mx.notFoundHandler != nil { - subr.NotFound(mx.notFoundHandler) - } - if ok && subr.methodNotAllowedHandler == nil && mx.methodNotAllowedHandler != nil { - subr.MethodNotAllowed(mx.methodNotAllowedHandler) - } - - // Wrap the sub-router in a handlerFunc to scope the request path for routing. - mountHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - rctx := RouteContext(r.Context()) - rctx.RoutePath = mx.nextRoutePath(rctx) - handler.ServeHTTP(w, r) - }) - - if pattern == "" || pattern[len(pattern)-1] != '/' { - mx.handle(mALL|mSTUB, pattern, mountHandler) - mx.handle(mALL|mSTUB, pattern+"/", mountHandler) - pattern += "/" - } - - method := mALL - subroutes, _ := handler.(Routes) - if subroutes != nil { - method |= mSTUB - } - n := mx.handle(method, pattern+"*", mountHandler) - - if subroutes != nil { - n.subroutes = subroutes - } -} - -// Routes returns a slice of routing information from the tree, -// useful for traversing available routes of a router. -func (mx *Mux) Routes() []Route { - return mx.tree.routes() -} - -// Middlewares returns a slice of middleware handler functions. -func (mx *Mux) Middlewares() Middlewares { - return mx.middlewares -} - -// Match searches the routing tree for a handler that matches the method/path. -// It's similar to routing a http request, but without executing the handler -// thereafter. -// -// Note: the *Context state is updated during execution, so manage -// the state carefully or make a NewRouteContext(). -func (mx *Mux) Match(rctx *Context, method, path string) bool { - m, ok := methodMap[method] - if !ok { - return false - } - - node, _, h := mx.tree.FindRoute(rctx, m, path) - - if node != nil && node.subroutes != nil { - rctx.RoutePath = mx.nextRoutePath(rctx) - return node.subroutes.Match(rctx, method, rctx.RoutePath) - } - - return h != nil -} - -// NotFoundHandler returns the default Mux 404 responder whenever a route -// cannot be found. -func (mx *Mux) NotFoundHandler() http.HandlerFunc { - if mx.notFoundHandler != nil { - return mx.notFoundHandler - } - return http.NotFound -} - -// MethodNotAllowedHandler returns the default Mux 405 responder whenever -// a method cannot be resolved for a route. -func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc { - if mx.methodNotAllowedHandler != nil { - return mx.methodNotAllowedHandler - } - return methodNotAllowedHandler -} - -// buildRouteHandler builds the single mux handler that is a chain of the middleware -// stack, as defined by calls to Use(), and the tree router (Mux) itself. After this -// point, no other middlewares can be registered on this Mux's stack. But you can still -// compose additional middlewares via Group()'s or using a chained middleware handler. -func (mx *Mux) buildRouteHandler() { - mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP)) -} - -// handle registers a http.Handler in the routing tree for a particular http method -// and routing pattern. -func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node { - if len(pattern) == 0 || pattern[0] != '/' { - panic(fmt.Sprintf("chi: routing pattern must begin with '/' in '%s'", pattern)) - } - - // Build the final routing handler for this Mux. - if !mx.inline && mx.handler == nil { - mx.buildRouteHandler() - } - - // Build endpoint handler with inline middlewares for the route - var h http.Handler - if mx.inline { - mx.handler = http.HandlerFunc(mx.routeHTTP) - h = Chain(mx.middlewares...).Handler(handler) - } else { - h = handler - } - - // Add the endpoint to the tree and return the node - return mx.tree.InsertRoute(method, pattern, h) -} - -// routeHTTP routes a http.Request through the Mux routing tree to serve -// the matching handler for a particular http method. -func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) { - // Grab the route context object - rctx := r.Context().Value(RouteCtxKey).(*Context) - - // The request routing path - routePath := rctx.RoutePath - if routePath == "" { - if r.URL.RawPath != "" { - routePath = r.URL.RawPath - } else { - routePath = r.URL.Path - } - } - - // Check if method is supported by chi - if rctx.RouteMethod == "" { - rctx.RouteMethod = r.Method - } - method, ok := methodMap[rctx.RouteMethod] - if !ok { - mx.MethodNotAllowedHandler().ServeHTTP(w, r) - return - } - - // Find the route - if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil { - h.ServeHTTP(w, r) - return - } - if rctx.methodNotAllowed { - mx.MethodNotAllowedHandler().ServeHTTP(w, r) - } else { - mx.NotFoundHandler().ServeHTTP(w, r) - } -} - -func (mx *Mux) nextRoutePath(rctx *Context) string { - routePath := "/" - nx := len(rctx.routeParams.Keys) - 1 // index of last param in list - if nx >= 0 && rctx.routeParams.Keys[nx] == "*" && len(rctx.routeParams.Values) > nx { - routePath += rctx.routeParams.Values[nx] - } - return routePath -} - -// Recursively update data on child routers. -func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) { - for _, r := range mx.tree.routes() { - subMux, ok := r.SubRoutes.(*Mux) - if !ok { - continue - } - fn(subMux) - } -} - -// methodNotAllowedHandler is a helper function to respond with a 405, -// method not allowed. -func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(405) - w.Write(nil) -} diff --git a/vendor/github.com/go-chi/chi/tree.go b/vendor/github.com/go-chi/chi/tree.go deleted file mode 100644 index 4dce0a3..0000000 --- a/vendor/github.com/go-chi/chi/tree.go +++ /dev/null @@ -1,847 +0,0 @@ -package chi - -// Radix tree implementation below is a based on the original work by -// Armon Dadgar in https://github.com/armon/go-radix/blob/master/radix.go -// (MIT licensed). It's been heavily modified for use as a HTTP routing tree. - -import ( - "fmt" - "math" - "net/http" - "regexp" - "sort" - "strconv" - "strings" -) - -type methodTyp int - -const ( - mSTUB methodTyp = 1 << iota - mCONNECT - mDELETE - mGET - mHEAD - mOPTIONS - mPATCH - mPOST - mPUT - mTRACE -) - -var mALL = mCONNECT | mDELETE | mGET | mHEAD | - mOPTIONS | mPATCH | mPOST | mPUT | mTRACE - -var methodMap = map[string]methodTyp{ - http.MethodConnect: mCONNECT, - http.MethodDelete: mDELETE, - http.MethodGet: mGET, - http.MethodHead: mHEAD, - http.MethodOptions: mOPTIONS, - http.MethodPatch: mPATCH, - http.MethodPost: mPOST, - http.MethodPut: mPUT, - http.MethodTrace: mTRACE, -} - -// RegisterMethod adds support for custom HTTP method handlers, available -// via Router#Method and Router#MethodFunc -func RegisterMethod(method string) { - if method == "" { - return - } - method = strings.ToUpper(method) - if _, ok := methodMap[method]; ok { - return - } - n := len(methodMap) - if n > strconv.IntSize { - panic(fmt.Sprintf("chi: max number of methods reached (%d)", strconv.IntSize)) - } - mt := methodTyp(math.Exp2(float64(n))) - methodMap[method] = mt - mALL |= mt -} - -type nodeTyp uint8 - -const ( - ntStatic nodeTyp = iota // /home - ntRegexp // /{id:[0-9]+} - ntParam // /{user} - ntCatchAll // /api/v1/* -) - -type node struct { - // node type: static, regexp, param, catchAll - typ nodeTyp - - // first byte of the prefix - label byte - - // first byte of the child prefix - tail byte - - // prefix is the common prefix we ignore - prefix string - - // regexp matcher for regexp nodes - rex *regexp.Regexp - - // HTTP handler endpoints on the leaf node - endpoints endpoints - - // subroutes on the leaf node - subroutes Routes - - // child nodes should be stored in-order for iteration, - // in groups of the node type. - children [ntCatchAll + 1]nodes -} - -// endpoints is a mapping of http method constants to handlers -// for a given route. -type endpoints map[methodTyp]*endpoint - -type endpoint struct { - // endpoint handler - handler http.Handler - - // pattern is the routing pattern for handler nodes - pattern string - - // parameter keys recorded on handler nodes - paramKeys []string -} - -func (s endpoints) Value(method methodTyp) *endpoint { - mh, ok := s[method] - if !ok { - mh = &endpoint{} - s[method] = mh - } - return mh -} - -func (n *node) InsertRoute(method methodTyp, pattern string, handler http.Handler) *node { - var parent *node - search := pattern - - for { - // Handle key exhaustion - if len(search) == 0 { - // Insert or update the node's leaf handler - n.setEndpoint(method, handler, pattern) - return n - } - - // We're going to be searching for a wild node next, - // in this case, we need to get the tail - var label = search[0] - var segTail byte - var segEndIdx int - var segTyp nodeTyp - var segRexpat string - if label == '{' || label == '*' { - segTyp, _, segRexpat, segTail, _, segEndIdx = patNextSegment(search) - } - - var prefix string - if segTyp == ntRegexp { - prefix = segRexpat - } - - // Look for the edge to attach to - parent = n - n = n.getEdge(segTyp, label, segTail, prefix) - - // No edge, create one - if n == nil { - child := &node{label: label, tail: segTail, prefix: search} - hn := parent.addChild(child, search) - hn.setEndpoint(method, handler, pattern) - - return hn - } - - // Found an edge to match the pattern - - if n.typ > ntStatic { - // We found a param node, trim the param from the search path and continue. - // This param/wild pattern segment would already be on the tree from a previous - // call to addChild when creating a new node. - search = search[segEndIdx:] - continue - } - - // Static nodes fall below here. - // Determine longest prefix of the search key on match. - commonPrefix := longestPrefix(search, n.prefix) - if commonPrefix == len(n.prefix) { - // the common prefix is as long as the current node's prefix we're attempting to insert. - // keep the search going. - search = search[commonPrefix:] - continue - } - - // Split the node - child := &node{ - typ: ntStatic, - prefix: search[:commonPrefix], - } - parent.replaceChild(search[0], segTail, child) - - // Restore the existing node - n.label = n.prefix[commonPrefix] - n.prefix = n.prefix[commonPrefix:] - child.addChild(n, n.prefix) - - // If the new key is a subset, set the method/handler on this node and finish. - search = search[commonPrefix:] - if len(search) == 0 { - child.setEndpoint(method, handler, pattern) - return child - } - - // Create a new edge for the node - subchild := &node{ - typ: ntStatic, - label: search[0], - prefix: search, - } - hn := child.addChild(subchild, search) - hn.setEndpoint(method, handler, pattern) - return hn - } -} - -// addChild appends the new `child` node to the tree using the `pattern` as the trie key. -// For a URL router like chi's, we split the static, param, regexp and wildcard segments -// into different nodes. In addition, addChild will recursively call itself until every -// pattern segment is added to the url pattern tree as individual nodes, depending on type. -func (n *node) addChild(child *node, prefix string) *node { - search := prefix - - // handler leaf node added to the tree is the child. - // this may be overridden later down the flow - hn := child - - // Parse next segment - segTyp, _, segRexpat, segTail, segStartIdx, segEndIdx := patNextSegment(search) - - // Add child depending on next up segment - switch segTyp { - - case ntStatic: - // Search prefix is all static (that is, has no params in path) - // noop - - default: - // Search prefix contains a param, regexp or wildcard - - if segTyp == ntRegexp { - rex, err := regexp.Compile(segRexpat) - if err != nil { - panic(fmt.Sprintf("chi: invalid regexp pattern '%s' in route param", segRexpat)) - } - child.prefix = segRexpat - child.rex = rex - } - - if segStartIdx == 0 { - // Route starts with a param - child.typ = segTyp - - if segTyp == ntCatchAll { - segStartIdx = -1 - } else { - segStartIdx = segEndIdx - } - if segStartIdx < 0 { - segStartIdx = len(search) - } - child.tail = segTail // for params, we set the tail - - if segStartIdx != len(search) { - // add static edge for the remaining part, split the end. - // its not possible to have adjacent param nodes, so its certainly - // going to be a static node next. - - search = search[segStartIdx:] // advance search position - - nn := &node{ - typ: ntStatic, - label: search[0], - prefix: search, - } - hn = child.addChild(nn, search) - } - - } else if segStartIdx > 0 { - // Route has some param - - // starts with a static segment - child.typ = ntStatic - child.prefix = search[:segStartIdx] - child.rex = nil - - // add the param edge node - search = search[segStartIdx:] - - nn := &node{ - typ: segTyp, - label: search[0], - tail: segTail, - } - hn = child.addChild(nn, search) - - } - } - - n.children[child.typ] = append(n.children[child.typ], child) - n.children[child.typ].Sort() - return hn -} - -func (n *node) replaceChild(label, tail byte, child *node) { - for i := 0; i < len(n.children[child.typ]); i++ { - if n.children[child.typ][i].label == label && n.children[child.typ][i].tail == tail { - n.children[child.typ][i] = child - n.children[child.typ][i].label = label - n.children[child.typ][i].tail = tail - return - } - } - panic("chi: replacing missing child") -} - -func (n *node) getEdge(ntyp nodeTyp, label, tail byte, prefix string) *node { - nds := n.children[ntyp] - for i := 0; i < len(nds); i++ { - if nds[i].label == label && nds[i].tail == tail { - if ntyp == ntRegexp && nds[i].prefix != prefix { - continue - } - return nds[i] - } - } - return nil -} - -func (n *node) setEndpoint(method methodTyp, handler http.Handler, pattern string) { - // Set the handler for the method type on the node - if n.endpoints == nil { - n.endpoints = make(endpoints, 0) - } - - paramKeys := patParamKeys(pattern) - - if method&mSTUB == mSTUB { - n.endpoints.Value(mSTUB).handler = handler - } - if method&mALL == mALL { - h := n.endpoints.Value(mALL) - h.handler = handler - h.pattern = pattern - h.paramKeys = paramKeys - for _, m := range methodMap { - h := n.endpoints.Value(m) - h.handler = handler - h.pattern = pattern - h.paramKeys = paramKeys - } - } else { - h := n.endpoints.Value(method) - h.handler = handler - h.pattern = pattern - h.paramKeys = paramKeys - } -} - -func (n *node) FindRoute(rctx *Context, method methodTyp, path string) (*node, endpoints, http.Handler) { - // Reset the context routing pattern and params - rctx.routePattern = "" - rctx.routeParams.Keys = rctx.routeParams.Keys[:0] - rctx.routeParams.Values = rctx.routeParams.Values[:0] - - // Find the routing handlers for the path - rn := n.findRoute(rctx, method, path) - if rn == nil { - return nil, nil, nil - } - - // Record the routing params in the request lifecycle - rctx.URLParams.Keys = append(rctx.URLParams.Keys, rctx.routeParams.Keys...) - rctx.URLParams.Values = append(rctx.URLParams.Values, rctx.routeParams.Values...) - - // Record the routing pattern in the request lifecycle - if rn.endpoints[method].pattern != "" { - rctx.routePattern = rn.endpoints[method].pattern - rctx.RoutePatterns = append(rctx.RoutePatterns, rctx.routePattern) - } - - return rn, rn.endpoints, rn.endpoints[method].handler -} - -// Recursive edge traversal by checking all nodeTyp groups along the way. -// It's like searching through a multi-dimensional radix trie. -func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node { - nn := n - search := path - - for t, nds := range nn.children { - ntyp := nodeTyp(t) - if len(nds) == 0 { - continue - } - - var xn *node - xsearch := search - - var label byte - if search != "" { - label = search[0] - } - - switch ntyp { - case ntStatic: - xn = nds.findEdge(label) - if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) { - continue - } - xsearch = xsearch[len(xn.prefix):] - - case ntParam, ntRegexp: - // short-circuit and return no matching route for empty param values - if xsearch == "" { - continue - } - - // serially loop through each node grouped by the tail delimiter - for idx := 0; idx < len(nds); idx++ { - xn = nds[idx] - - // label for param nodes is the delimiter byte - p := strings.IndexByte(xsearch, xn.tail) - - if p < 0 { - if xn.tail == '/' { - p = len(xsearch) - } else { - continue - } - } - - if ntyp == ntRegexp && xn.rex != nil { - if xn.rex.Match([]byte(xsearch[:p])) == false { - continue - } - } else if strings.IndexByte(xsearch[:p], '/') != -1 { - // avoid a match across path segments - continue - } - - rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p]) - xsearch = xsearch[p:] - break - } - - default: - // catch-all nodes - rctx.routeParams.Values = append(rctx.routeParams.Values, search) - xn = nds[0] - xsearch = "" - } - - if xn == nil { - continue - } - - // did we find it yet? - if len(xsearch) == 0 { - if xn.isLeaf() { - h, _ := xn.endpoints[method] - if h != nil && h.handler != nil { - rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...) - return xn - } - - // flag that the routing context found a route, but not a corresponding - // supported method - rctx.methodNotAllowed = true - } - } - - // recursively find the next node.. - fin := xn.findRoute(rctx, method, xsearch) - if fin != nil { - return fin - } - - // Did not find final handler, let's remove the param here if it was set - if xn.typ > ntStatic { - if len(rctx.routeParams.Values) > 0 { - rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1] - } - } - - } - - return nil -} - -func (n *node) findEdge(ntyp nodeTyp, label byte) *node { - nds := n.children[ntyp] - num := len(nds) - idx := 0 - - switch ntyp { - case ntStatic, ntParam, ntRegexp: - i, j := 0, num-1 - for i <= j { - idx = i + (j-i)/2 - if label > nds[idx].label { - i = idx + 1 - } else if label < nds[idx].label { - j = idx - 1 - } else { - i = num // breaks cond - } - } - if nds[idx].label != label { - return nil - } - return nds[idx] - - default: // catch all - return nds[idx] - } -} - -func (n *node) isEmpty() bool { - for _, nds := range n.children { - if len(nds) > 0 { - return false - } - } - return true -} - -func (n *node) isLeaf() bool { - return n.endpoints != nil -} - -func (n *node) findPattern(pattern string) bool { - nn := n - for _, nds := range nn.children { - if len(nds) == 0 { - continue - } - - n = nn.findEdge(nds[0].typ, pattern[0]) - if n == nil { - continue - } - - var idx int - var xpattern string - - switch n.typ { - case ntStatic: - idx = longestPrefix(pattern, n.prefix) - if idx < len(n.prefix) { - continue - } - - case ntParam, ntRegexp: - idx = strings.IndexByte(pattern, '}') + 1 - - case ntCatchAll: - idx = longestPrefix(pattern, "*") - - default: - panic("chi: unknown node type") - } - - xpattern = pattern[idx:] - if len(xpattern) == 0 { - return true - } - - return n.findPattern(xpattern) - } - return false -} - -func (n *node) routes() []Route { - rts := []Route{} - - n.walk(func(eps endpoints, subroutes Routes) bool { - if eps[mSTUB] != nil && eps[mSTUB].handler != nil && subroutes == nil { - return false - } - - // Group methodHandlers by unique patterns - pats := make(map[string]endpoints, 0) - - for mt, h := range eps { - if h.pattern == "" { - continue - } - p, ok := pats[h.pattern] - if !ok { - p = endpoints{} - pats[h.pattern] = p - } - p[mt] = h - } - - for p, mh := range pats { - hs := make(map[string]http.Handler, 0) - if mh[mALL] != nil && mh[mALL].handler != nil { - hs["*"] = mh[mALL].handler - } - - for mt, h := range mh { - if h.handler == nil { - continue - } - m := methodTypString(mt) - if m == "" { - continue - } - hs[m] = h.handler - } - - rt := Route{p, hs, subroutes} - rts = append(rts, rt) - } - - return false - }) - - return rts -} - -func (n *node) walk(fn func(eps endpoints, subroutes Routes) bool) bool { - // Visit the leaf values if any - if (n.endpoints != nil || n.subroutes != nil) && fn(n.endpoints, n.subroutes) { - return true - } - - // Recurse on the children - for _, ns := range n.children { - for _, cn := range ns { - if cn.walk(fn) { - return true - } - } - } - return false -} - -// patNextSegment returns the next segment details from a pattern: -// node type, param key, regexp string, param tail byte, param starting index, param ending index -func patNextSegment(pattern string) (nodeTyp, string, string, byte, int, int) { - ps := strings.Index(pattern, "{") - ws := strings.Index(pattern, "*") - - if ps < 0 && ws < 0 { - return ntStatic, "", "", 0, 0, len(pattern) // we return the entire thing - } - - // Sanity check - if ws >= 0 && ws != len(pattern)-1 { - panic("chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead") - } - if ps >= 0 && ws >= 0 && ws < ps { - panic("chi: wildcard '*' must be the last pattern in a route, otherwise use a '{param}'") - } - - var tail byte = '/' // Default endpoint tail to / byte - - if ps >= 0 { - // Param/Regexp pattern is next - nt := ntParam - - // Read to closing } taking into account opens and closes in curl count (cc) - cc := 0 - pe := ps - for i, c := range pattern[ps:] { - if c == '{' { - cc++ - } else if c == '}' { - cc-- - if cc == 0 { - pe = ps + i - break - } - } - } - if pe == ps { - panic("chi: route param closing delimiter '}' is missing") - } - - key := pattern[ps+1 : pe] - pe++ // set end to next position - - if pe < len(pattern) { - tail = pattern[pe] - } - - var rexpat string - if idx := strings.Index(key, ":"); idx >= 0 { - nt = ntRegexp - rexpat = key[idx+1:] - key = key[:idx] - } - - if len(rexpat) > 0 { - if rexpat[0] != '^' { - rexpat = "^" + rexpat - } - if rexpat[len(rexpat)-1] != '$' { - rexpat = rexpat + "$" - } - } - - return nt, key, rexpat, tail, ps, pe - } - - // Wildcard pattern as finale - // TODO: should we panic if there is stuff after the * ??? - return ntCatchAll, "*", "", 0, ws, len(pattern) -} - -func patParamKeys(pattern string) []string { - pat := pattern - paramKeys := []string{} - for { - ptyp, paramKey, _, _, _, e := patNextSegment(pat) - if ptyp == ntStatic { - return paramKeys - } - for i := 0; i < len(paramKeys); i++ { - if paramKeys[i] == paramKey { - panic(fmt.Sprintf("chi: routing pattern '%s' contains duplicate param key, '%s'", pattern, paramKey)) - } - } - paramKeys = append(paramKeys, paramKey) - pat = pat[e:] - } -} - -// longestPrefix finds the length of the shared prefix -// of two strings -func longestPrefix(k1, k2 string) int { - max := len(k1) - if l := len(k2); l < max { - max = l - } - var i int - for i = 0; i < max; i++ { - if k1[i] != k2[i] { - break - } - } - return i -} - -func methodTypString(method methodTyp) string { - for s, t := range methodMap { - if method == t { - return s - } - } - return "" -} - -type nodes []*node - -// Sort the list of nodes by label -func (ns nodes) Sort() { sort.Sort(ns); ns.tailSort() } -func (ns nodes) Len() int { return len(ns) } -func (ns nodes) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] } -func (ns nodes) Less(i, j int) bool { return ns[i].label < ns[j].label } - -// tailSort pushes nodes with '/' as the tail to the end of the list for param nodes. -// The list order determines the traversal order. -func (ns nodes) tailSort() { - for i := len(ns) - 1; i >= 0; i-- { - if ns[i].typ > ntStatic && ns[i].tail == '/' { - ns.Swap(i, len(ns)-1) - return - } - } -} - -func (ns nodes) findEdge(label byte) *node { - num := len(ns) - idx := 0 - i, j := 0, num-1 - for i <= j { - idx = i + (j-i)/2 - if label > ns[idx].label { - i = idx + 1 - } else if label < ns[idx].label { - j = idx - 1 - } else { - i = num // breaks cond - } - } - if ns[idx].label != label { - return nil - } - return ns[idx] -} - -// Route describes the details of a routing handler. -type Route struct { - Pattern string - Handlers map[string]http.Handler - SubRoutes Routes -} - -// WalkFunc is the type of the function called for each method and route visited by Walk. -type WalkFunc func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error - -// Walk walks any router tree that implements Routes interface. -func Walk(r Routes, walkFn WalkFunc) error { - return walk(r, walkFn, "") -} - -func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.Handler) http.Handler) error { - for _, route := range r.Routes() { - mws := make([]func(http.Handler) http.Handler, len(parentMw)) - copy(mws, parentMw) - mws = append(mws, r.Middlewares()...) - - if route.SubRoutes != nil { - if err := walk(route.SubRoutes, walkFn, parentRoute+route.Pattern, mws...); err != nil { - return err - } - continue - } - - for method, handler := range route.Handlers { - if method == "*" { - // Ignore a "catchAll" method, since we pass down all the specific methods for each route. - continue - } - - fullRoute := parentRoute + route.Pattern - - if chain, ok := handler.(*ChainHandler); ok { - if err := walkFn(method, fullRoute, chain.Endpoint, append(mws, chain.Middlewares...)...); err != nil { - return err - } - } else { - if err := walkFn(method, fullRoute, handler, mws...); err != nil { - return err - } - } - } - } - - return nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/.gitignore b/vendor/github.com/go-sql-driver/mysql/.gitignore deleted file mode 100644 index 2de28da..0000000 --- a/vendor/github.com/go-sql-driver/mysql/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -Icon? -ehthumbs.db -Thumbs.db -.idea diff --git a/vendor/github.com/go-sql-driver/mysql/AUTHORS b/vendor/github.com/go-sql-driver/mysql/AUTHORS deleted file mode 100644 index 4021b96..0000000 --- a/vendor/github.com/go-sql-driver/mysql/AUTHORS +++ /dev/null @@ -1,142 +0,0 @@ -# This is the official list of Go-MySQL-Driver authors for copyright purposes. - -# If you are submitting a patch, please add your name or the name of the -# organization which holds the copyright to this list in alphabetical order. - -# Names should be added to this file as -# Name -# The email address is not required for organizations. -# Please keep the list sorted. - - -# Individual Persons - -Aaron Hopkins -Achille Roussel -Aidan -Alex Snast -Alexey Palazhchenko -Andrew Reid -Animesh Ray -Arne Hormann -Ariel Mashraki -Asta Xie -Brian Hendriks -Bulat Gaifullin -Caine Jette -Carlos Nieto -Chris Kirkland -Chris Moos -Craig Wilson -Daemonxiao <735462752 at qq.com> -Daniel Montoya -Daniel Nichter -Daniël van Eeden -Dave Protasowski -DisposaBoy -Egor Smolyakov -Erwan Martin -Evan Elias -Evan Shaw -Frederick Mayle -Gustavo Kristic -Gusted -Hajime Nakagami -Hanno Braun -Henri Yandell -Hirotaka Yamamoto -Huyiguang -ICHINOSE Shogo -Ilia Cimpoes -INADA Naoki -Jacek Szwec -James Harr -Janek Vedock -Jason Ng -Jean-Yves Pellé -Jeff Hodges -Jeffrey Charles -Jennifer Purevsuren -Jerome Meyer -Jiajia Zhong -Jian Zhen -Joshua Prunier -Julien Lefevre -Julien Schmidt -Justin Li -Justin Nuß -Kamil Dziedzic -Kei Kamikawa -Kevin Malachowski -Kieron Woodhouse -Lance Tian -Lennart Rudolph -Leonardo YongUk Kim -Linh Tran Tuan -Lion Yang -Luca Looz -Lucas Liu -Lunny Xiao -Luke Scott -Maciej Zimnoch -Michael Woolnough -Nathanial Murphy -Nicola Peduzzi -Oliver Bone -Olivier Mengué -oscarzhao -Paul Bonser -Paulius Lozys -Peter Schultz -Phil Porada -Rebecca Chin -Reed Allman -Richard Wilkes -Robert Russell -Runrioter Wung -Samantha Frank -Santhosh Kumar Tekuri -Sho Iizuka -Sho Ikeda -Shuode Li -Simon J Mudd -Soroush Pour -Stan Putrya -Stanley Gunawan -Steven Hartland -Tan Jinhua <312841925 at qq.com> -Tetsuro Aoki -Thomas Wodarek -Tim Ruffles -Tom Jenkinson -Vladimir Kovpak -Vladyslav Zhelezniak -Xiangyu Hu -Xiaobing Jiang -Xiuming Chen -Xuehong Chan -Zhang Xiang -Zhenye Xie -Zhixin Wen -Ziheng Lyu - -# Organizations - -Barracuda Networks, Inc. -Counting Ltd. -DigitalOcean Inc. -Dolthub Inc. -dyves labs AG -Facebook Inc. -GitHub Inc. -Google Inc. -InfoSum Ltd. -Keybase Inc. -Microsoft Corp. -Multiplay Ltd. -Percona LLC -PingCAP Inc. -Pivotal Inc. -Shattered Silicon Ltd. -Stripe Inc. -Zendesk Inc. diff --git a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md deleted file mode 100644 index 0c9bd9b..0000000 --- a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md +++ /dev/null @@ -1,308 +0,0 @@ -## Version 1.8.1 (2024-03-26) - -Bugfixes: - -- fix race condition when context is canceled in [#1562](https://github.com/go-sql-driver/mysql/pull/1562) and [#1570](https://github.com/go-sql-driver/mysql/pull/1570) - -## Version 1.8.0 (2024-03-09) - -Major Changes: - -- Use `SET NAMES charset COLLATE collation`. by @methane in [#1437](https://github.com/go-sql-driver/mysql/pull/1437) - - Older go-mysql-driver used `collation_id` in the handshake packet. But it caused collation mismatch in some situation. - - If you don't specify charset nor collation, go-mysql-driver sends `SET NAMES utf8mb4` for new connection. This uses server's default collation for utf8mb4. - - If you specify charset, go-mysql-driver sends `SET NAMES `. This uses the server's default collation for ``. - - If you specify collation and/or charset, go-mysql-driver sends `SET NAMES charset COLLATE collation`. -- PathEscape dbname in DSN. by @methane in [#1432](https://github.com/go-sql-driver/mysql/pull/1432) - - This is backward incompatible in rare case. Check your DSN. -- Drop Go 1.13-17 support by @methane in [#1420](https://github.com/go-sql-driver/mysql/pull/1420) - - Use Go 1.18+ -- Parse numbers on text protocol too by @methane in [#1452](https://github.com/go-sql-driver/mysql/pull/1452) - - When text protocol is used, go-mysql-driver passed bare `[]byte` to database/sql for avoid unnecessary allocation and conversion. - - If user specified `*any` to `Scan()`, database/sql passed the `[]byte` into the target variable. - - This confused users because most user doesn't know when text/binary protocol used. - - go-mysql-driver 1.8 converts integer/float values into int64/double even in text protocol. This doesn't increase allocation compared to `[]byte` and conversion cost is negatable. -- New options start using the Functional Option Pattern to avoid increasing technical debt in the Config object. Future version may introduce Functional Option for existing options, but not for now. - - Make TimeTruncate functional option by @methane in [1552](https://github.com/go-sql-driver/mysql/pull/1552) - - Add BeforeConnect callback to configuration object by @ItalyPaleAle in [#1469](https://github.com/go-sql-driver/mysql/pull/1469) - - -Other changes: - -- Adding DeregisterDialContext to prevent memory leaks with dialers we don't need anymore by @jypelle in https://github.com/go-sql-driver/mysql/pull/1422 -- Make logger configurable per connection by @frozenbonito in https://github.com/go-sql-driver/mysql/pull/1408 -- Fix ColumnType.DatabaseTypeName for mediumint unsigned by @evanelias in https://github.com/go-sql-driver/mysql/pull/1428 -- Add connection attributes by @Daemonxiao in https://github.com/go-sql-driver/mysql/pull/1389 -- Stop `ColumnTypeScanType()` from returning `sql.RawBytes` by @methane in https://github.com/go-sql-driver/mysql/pull/1424 -- Exec() now provides access to status of multiple statements. by @mherr-google in https://github.com/go-sql-driver/mysql/pull/1309 -- Allow to change (or disable) the default driver name for registration by @dolmen in https://github.com/go-sql-driver/mysql/pull/1499 -- Add default connection attribute '_server_host' by @oblitorum in https://github.com/go-sql-driver/mysql/pull/1506 -- QueryUnescape DSN ConnectionAttribute value by @zhangyangyu in https://github.com/go-sql-driver/mysql/pull/1470 -- Add client_ed25519 authentication by @Gusted in https://github.com/go-sql-driver/mysql/pull/1518 - -## Version 1.7.1 (2023-04-25) - -Changes: - - - bump actions/checkout@v3 and actions/setup-go@v3 (#1375) - - Add go1.20 and mariadb10.11 to the testing matrix (#1403) - - Increase default maxAllowedPacket size. (#1411) - -Bugfixes: - - - Use SET syntax as specified in the MySQL documentation (#1402) - - -## Version 1.7 (2022-11-29) - -Changes: - - - Drop support of Go 1.12 (#1211) - - Refactoring `(*textRows).readRow` in a more clear way (#1230) - - util: Reduce boundary check in escape functions. (#1316) - - enhancement for mysqlConn handleAuthResult (#1250) - -New Features: - - - support Is comparison on MySQLError (#1210) - - return unsigned in database type name when necessary (#1238) - - Add API to express like a --ssl-mode=PREFERRED MySQL client (#1370) - - Add SQLState to MySQLError (#1321) - -Bugfixes: - - - Fix parsing 0 year. (#1257) - - -## Version 1.6 (2021-04-01) - -Changes: - - - Migrate the CI service from travis-ci to GitHub Actions (#1176, #1183, #1190) - - `NullTime` is deprecated (#960, #1144) - - Reduce allocations when building SET command (#1111) - - Performance improvement for time formatting (#1118) - - Performance improvement for time parsing (#1098, #1113) - -New Features: - - - Implement `driver.Validator` interface (#1106, #1174) - - Support returning `uint64` from `Valuer` in `ConvertValue` (#1143) - - Add `json.RawMessage` for converter and prepared statement (#1059) - - Interpolate `json.RawMessage` as `string` (#1058) - - Implements `CheckNamedValue` (#1090) - -Bugfixes: - - - Stop rounding times (#1121, #1172) - - Put zero filler into the SSL handshake packet (#1066) - - Fix checking cancelled connections back into the connection pool (#1095) - - Fix remove last 0 byte for mysql_old_password when password is empty (#1133) - - -## Version 1.5 (2020-01-07) - -Changes: - - - Dropped support Go 1.9 and lower (#823, #829, #886, #1016, #1017) - - Improve buffer handling (#890) - - Document potentially insecure TLS configs (#901) - - Use a double-buffering scheme to prevent data races (#943) - - Pass uint64 values without converting them to string (#838, #955) - - Update collations and make utf8mb4 default (#877, #1054) - - Make NullTime compatible with sql.NullTime in Go 1.13+ (#995) - - Removed CloudSQL support (#993, #1007) - - Add Go Module support (#1003) - -New Features: - - - Implement support of optional TLS (#900) - - Check connection liveness (#934, #964, #997, #1048, #1051, #1052) - - Implement Connector Interface (#941, #958, #1020, #1035) - -Bugfixes: - - - Mark connections as bad on error during ping (#875) - - Mark connections as bad on error during dial (#867) - - Fix connection leak caused by rapid context cancellation (#1024) - - Mark connections as bad on error during Conn.Prepare (#1030) - - -## Version 1.4.1 (2018-11-14) - -Bugfixes: - - - Fix TIME format for binary columns (#818) - - Fix handling of empty auth plugin names (#835) - - Fix caching_sha2_password with empty password (#826) - - Fix canceled context broke mysqlConn (#862) - - Fix OldAuthSwitchRequest support (#870) - - Fix Auth Response packet for cleartext password (#887) - -## Version 1.4 (2018-06-03) - -Changes: - - - Documentation fixes (#530, #535, #567) - - Refactoring (#575, #579, #580, #581, #603, #615, #704) - - Cache column names (#444) - - Sort the DSN parameters in DSNs generated from a config (#637) - - Allow native password authentication by default (#644) - - Use the default port if it is missing in the DSN (#668) - - Removed the `strict` mode (#676) - - Do not query `max_allowed_packet` by default (#680) - - Dropped support Go 1.6 and lower (#696) - - Updated `ConvertValue()` to match the database/sql/driver implementation (#760) - - Document the usage of `0000-00-00T00:00:00` as the time.Time zero value (#783) - - Improved the compatibility of the authentication system (#807) - -New Features: - - - Multi-Results support (#537) - - `rejectReadOnly` DSN option (#604) - - `context.Context` support (#608, #612, #627, #761) - - Transaction isolation level support (#619, #744) - - Read-Only transactions support (#618, #634) - - `NewConfig` function which initializes a config with default values (#679) - - Implemented the `ColumnType` interfaces (#667, #724) - - Support for custom string types in `ConvertValue` (#623) - - Implemented `NamedValueChecker`, improving support for uint64 with high bit set (#690, #709, #710) - - `caching_sha2_password` authentication plugin support (#794, #800, #801, #802) - - Implemented `driver.SessionResetter` (#779) - - `sha256_password` authentication plugin support (#808) - -Bugfixes: - - - Use the DSN hostname as TLS default ServerName if `tls=true` (#564, #718) - - Fixed LOAD LOCAL DATA INFILE for empty files (#590) - - Removed columns definition cache since it sometimes cached invalid data (#592) - - Don't mutate registered TLS configs (#600) - - Make RegisterTLSConfig concurrency-safe (#613) - - Handle missing auth data in the handshake packet correctly (#646) - - Do not retry queries when data was written to avoid data corruption (#302, #736) - - Cache the connection pointer for error handling before invalidating it (#678) - - Fixed imports for appengine/cloudsql (#700) - - Fix sending STMT_LONG_DATA for 0 byte data (#734) - - Set correct capacity for []bytes read from length-encoded strings (#766) - - Make RegisterDial concurrency-safe (#773) - - -## Version 1.3 (2016-12-01) - -Changes: - - - Go 1.1 is no longer supported - - Use decimals fields in MySQL to format time types (#249) - - Buffer optimizations (#269) - - TLS ServerName defaults to the host (#283) - - Refactoring (#400, #410, #437) - - Adjusted documentation for second generation CloudSQL (#485) - - Documented DSN system var quoting rules (#502) - - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512) - -New Features: - - - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249) - - Support for returning table alias on Columns() (#289, #359, #382) - - Placeholder interpolation, can be activated with the DSN parameter `interpolateParams=true` (#309, #318, #490) - - Support for uint64 parameters with high bit set (#332, #345) - - Cleartext authentication plugin support (#327) - - Exported ParseDSN function and the Config struct (#403, #419, #429) - - Read / Write timeouts (#401) - - Support for JSON field type (#414) - - Support for multi-statements and multi-results (#411, #431) - - DSN parameter to set the driver-side max_allowed_packet value manually (#489) - - Native password authentication plugin support (#494, #524) - -Bugfixes: - - - Fixed handling of queries without columns and rows (#255) - - Fixed a panic when SetKeepAlive() failed (#298) - - Handle ERR packets while reading rows (#321) - - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349) - - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356) - - Actually zero out bytes in handshake response (#378) - - Fixed race condition in registering LOAD DATA INFILE handler (#383) - - Fixed tests with MySQL 5.7.9+ (#380) - - QueryUnescape TLS config names (#397) - - Fixed "broken pipe" error by writing to closed socket (#390) - - Fixed LOAD LOCAL DATA INFILE buffering (#424) - - Fixed parsing of floats into float64 when placeholders are used (#434) - - Fixed DSN tests with Go 1.7+ (#459) - - Handle ERR packets while waiting for EOF (#473) - - Invalidate connection on error while discarding additional results (#513) - - Allow terminating packets of length 0 (#516) - - -## Version 1.2 (2014-06-03) - -Changes: - - - We switched back to a "rolling release". `go get` installs the current master branch again - - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver - - Exported errors to allow easy checking from application code - - Enabled TCP Keepalives on TCP connections - - Optimized INFILE handling (better buffer size calculation, lazy init, ...) - - The DSN parser also checks for a missing separating slash - - Faster binary date / datetime to string formatting - - Also exported the MySQLWarning type - - mysqlConn.Close returns the first error encountered instead of ignoring all errors - - writePacket() automatically writes the packet size to the header - - readPacket() uses an iterative approach instead of the recursive approach to merge split packets - -New Features: - - - `RegisterDial` allows the usage of a custom dial function to establish the network connection - - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter - - Logging of critical errors is configurable with `SetLogger` - - Google CloudSQL support - -Bugfixes: - - - Allow more than 32 parameters in prepared statements - - Various old_password fixes - - Fixed TestConcurrent test to pass Go's race detection - - Fixed appendLengthEncodedInteger for large numbers - - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo) - - -## Version 1.1 (2013-11-02) - -Changes: - - - Go-MySQL-Driver now requires Go 1.1 - - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore - - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors - - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")` - - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'. - - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries - - Optimized the buffer for reading - - stmt.Query now caches column metadata - - New Logo - - Changed the copyright header to include all contributors - - Improved the LOAD INFILE documentation - - The driver struct is now exported to make the driver directly accessible - - Refactored the driver tests - - Added more benchmarks and moved all to a separate file - - Other small refactoring - -New Features: - - - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure - - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs - - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used - -Bugfixes: - - - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification - - Convert to DB timezone when inserting `time.Time` - - Split packets (more than 16MB) are now merged correctly - - Fixed false positive `io.EOF` errors when the data was fully read - - Avoid panics on reuse of closed connections - - Fixed empty string producing false nil values - - Fixed sign byte for positive TIME fields - - -## Version 1.0 (2013-05-14) - -Initial Release diff --git a/vendor/github.com/go-sql-driver/mysql/LICENSE b/vendor/github.com/go-sql-driver/mysql/LICENSE deleted file mode 100644 index 14e2f77..0000000 --- a/vendor/github.com/go-sql-driver/mysql/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/go-sql-driver/mysql/README.md b/vendor/github.com/go-sql-driver/mysql/README.md deleted file mode 100644 index 4968cb0..0000000 --- a/vendor/github.com/go-sql-driver/mysql/README.md +++ /dev/null @@ -1,581 +0,0 @@ -# Go-MySQL-Driver - -A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package - -![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") - ---------------------------------------- - * [Features](#features) - * [Requirements](#requirements) - * [Installation](#installation) - * [Usage](#usage) - * [DSN (Data Source Name)](#dsn-data-source-name) - * [Password](#password) - * [Protocol](#protocol) - * [Address](#address) - * [Parameters](#parameters) - * [Examples](#examples) - * [Connection pool and timeouts](#connection-pool-and-timeouts) - * [context.Context Support](#contextcontext-support) - * [ColumnType Support](#columntype-support) - * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support) - * [time.Time support](#timetime-support) - * [Unicode support](#unicode-support) - * [Testing / Development](#testing--development) - * [License](#license) - ---------------------------------------- - -## Features - * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance") - * Native Go implementation. No C-bindings, just pure Go - * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc) - * Automatic handling of broken connections - * Automatic Connection Pooling *(by database/sql package)* - * Supports queries larger than 16MB - * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support. - * Intelligent `LONG DATA` handling in prepared statements - * Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support - * Optional `time.Time` parsing - * Optional placeholder interpolation - -## Requirements - -* Go 1.19 or higher. We aim to support the 3 latest versions of Go. -* MySQL (5.7+) and MariaDB (10.3+) are supported. -* [TiDB](https://github.com/pingcap/tidb) is supported by PingCAP. - * Do not ask questions about TiDB in our issue tracker or forum. - * [Document](https://docs.pingcap.com/tidb/v6.1/dev-guide-sample-application-golang) - * [Forum](https://ask.pingcap.com/) -* go-mysql would work with Percona Server, Google CloudSQL or Sphinx (2.2.3+). - * Maintainers won't support them. Do not expect issues are investigated and resolved by maintainers. - * Investigate issues yourself and please send a pull request to fix it. - ---------------------------------------- - -## Installation -Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: -```bash -go get -u github.com/go-sql-driver/mysql -``` -Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. - -## Usage -_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. - -Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: - -```go -import ( - "database/sql" - "time" - - _ "github.com/go-sql-driver/mysql" -) - -// ... - -db, err := sql.Open("mysql", "user:password@/dbname") -if err != nil { - panic(err) -} -// See "Important settings" section. -db.SetConnMaxLifetime(time.Minute * 3) -db.SetMaxOpenConns(10) -db.SetMaxIdleConns(10) -``` - -[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples"). - -### Important settings - -`db.SetConnMaxLifetime()` is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too. - -`db.SetMaxOpenConns()` is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server. - -`db.SetMaxIdleConns()` is recommended to be set same to `db.SetMaxOpenConns()`. When it is smaller than `SetMaxOpenConns()`, connections can be opened and closed much more frequently than you expect. Idle connections can be closed by the `db.SetConnMaxLifetime()`. If you want to close idle connections more rapidly, you can use `db.SetConnMaxIdleTime()` since Go 1.15. - - -### DSN (Data Source Name) - -The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets): -``` -[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] -``` - -A DSN in its fullest form: -``` -username:password@protocol(address)/dbname?param=value -``` - -Except for the databasename, all values are optional. So the minimal DSN is: -``` -/dbname -``` - -If you do not want to preselect a database, leave `dbname` empty: -``` -/ -``` -This has the same effect as an empty DSN string: -``` - -``` - -`dbname` is escaped by [PathEscape()](https://pkg.go.dev/net/url#PathEscape) since v1.8.0. If your database name is `dbname/withslash`, it becomes: - -``` -/dbname%2Fwithslash -``` - -Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct. - -#### Password -Passwords can consist of any character. Escaping is **not** necessary. - -#### Protocol -See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. -In general you should use a Unix domain socket if available and TCP otherwise for best performance. - -#### Address -For TCP and UDP networks, addresses have the form `host[:port]`. -If `port` is omitted, the default port will be used. -If `host` is a literal IPv6 address, it must be enclosed in square brackets. -The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. - -For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`. - -#### Parameters -*Parameters are case-sensitive!* - -Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`. - -##### `allowAllFiles` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files. -[*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local) - -##### `allowCleartextPasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowCleartextPasswords=true` allows using the [cleartext client side plugin](https://dev.mysql.com/doc/en/cleartext-pluggable-authentication.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network. - - -##### `allowFallbackToPlaintext` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowFallbackToPlaintext=true` acts like a `--ssl-mode=PREFERRED` MySQL client as described in [Command Options for Connecting to the Server](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode) - -##### `allowNativePasswords` - -``` -Type: bool -Valid Values: true, false -Default: true -``` -`allowNativePasswords=false` disallows the usage of MySQL native password method. - -##### `allowOldPasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` -`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords). - -##### `charset` - -``` -Type: string -Valid Values: -Default: none -``` - -Sets the charset used for client-server interaction (`"SET NAMES "`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset fails. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`). - -See also [Unicode Support](#unicode-support). - -##### `checkConnLiveness` - -``` -Type: bool -Valid Values: true, false -Default: true -``` - -On supported platforms connections retrieved from the connection pool are checked for liveness before using them. If the check fails, the respective connection is marked as bad and the query retried with another connection. -`checkConnLiveness=false` disables this liveness check of connections. - -##### `collation` - -``` -Type: string -Valid Values: -Default: utf8mb4_general_ci -``` - -Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail. - -A list of valid charsets for a server is retrievable with `SHOW COLLATION`. - -The default collation (`utf8mb4_general_ci`) is supported from MySQL 5.5. You should use an older collation (e.g. `utf8_general_ci`) for older MySQL. - -Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)). - -See also [Unicode Support](#unicode-support). - -##### `clientFoundRows` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed. - -##### `columnsWithAlias` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -When `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example: - -``` -SELECT u.id FROM users as u -``` - -will return `u.id` instead of just `id` if `columnsWithAlias=true`. - -##### `interpolateParams` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`. - -*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!* - -##### `loc` - -``` -Type: string -Valid Values: -Default: UTC -``` - -Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details. - -Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter. - -Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. - -##### `timeTruncate` - -``` -Type: duration -Default: 0 -``` - -[Truncate time values](https://pkg.go.dev/time#Duration.Truncate) to the specified duration. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - -##### `maxAllowedPacket` -``` -Type: decimal number -Default: 64*1024*1024 -``` - -Max packet size allowed in bytes. The default value is 64 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*. - -##### `multiStatements` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -Allow multiple statements in one query. This can be used to bach multiple queries. Use [Rows.NextResultSet()](https://pkg.go.dev/database/sql#Rows.NextResultSet) to get result of the second and subsequent queries. - -When `multiStatements` is used, `?` parameters must only be used in the first statement. [interpolateParams](#interpolateparams) can be used to avoid this limitation unless prepared statement is used explicitly. - -It's possible to access the last inserted ID and number of affected rows for multiple statements by using `sql.Conn.Raw()` and the `mysql.Result`. For example: - -```go -conn, _ := db.Conn(ctx) -conn.Raw(func(conn any) error { - ex := conn.(driver.Execer) - res, err := ex.Exec(` - UPDATE point SET x = 1 WHERE y = 2; - UPDATE point SET x = 2 WHERE y = 3; - `, nil) - // Both slices have 2 elements. - log.Print(res.(mysql.Result).AllRowsAffected()) - log.Print(res.(mysql.Result).AllLastInsertIds()) -}) -``` - -##### `parseTime` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string` -The date or datetime like `0000-00-00 00:00:00` is converted into zero value of `time.Time`. - - -##### `readTimeout` - -``` -Type: duration -Default: 0 -``` - -I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - -##### `rejectReadOnly` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - - -`rejectReadOnly=true` causes the driver to reject read-only connections. This -is for a possible race condition during an automatic failover, where the mysql -client gets connected to a read-only replica after the failover. - -Note that this should be a fairly rare case, as an automatic failover normally -happens when the primary is down, and the race condition shouldn't happen -unless it comes back up online as soon as the failover is kicked off. On the -other hand, when this happens, a MySQL application can get stuck on a -read-only connection until restarted. It is however fairly easy to reproduce, -for example, using a manual failover on AWS Aurora's MySQL-compatible cluster. - -If you are not relying on read-only transactions to reject writes that aren't -supposed to happen, setting this on some MySQL providers (such as AWS Aurora) -is safer for failovers. - -Note that ERROR 1290 can be returned for a `read-only` server and this option will -cause a retry for that error. However the same error number is used for some -other cases. You should ensure your application will never cause an ERROR 1290 -except for `read-only` mode when enabling this option. - - -##### `serverPubKey` - -``` -Type: string -Valid Values: -Default: none -``` - -Server public keys can be registered with [`mysql.RegisterServerPubKey`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterServerPubKey), which can then be used by the assigned name in the DSN. -Public keys are used to transmit encrypted data, e.g. for authentication. -If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required. - - -##### `timeout` - -``` -Type: duration -Default: OS default -``` - -Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - - -##### `tls` - -``` -Type: bool / string -Valid Values: true, false, skip-verify, preferred, -Default: false -``` - -`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). - - -##### `writeTimeout` - -``` -Type: duration -Default: 0 -``` - -I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - -##### `connectionAttributes` - -``` -Type: comma-delimited string of user-defined "key:value" pairs -Valid Values: (:,:,...) -Default: none -``` - -[Connection attributes](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html) are key-value pairs that application programs can pass to the server at connect time. - -##### System Variables - -Any other parameters are interpreted as system variables: - * `=`: `SET =` - * `=`: `SET =` - * `=%27%27`: `SET =''` - -Rules: -* The values for string variables must be quoted with `'`. -* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! - (which implies values of string variables must be wrapped with `%27`). - -Examples: - * `autocommit=1`: `SET autocommit=1` - * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` - * [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'` - - -#### Examples -``` -user@unix(/path/to/socket)/dbname -``` - -``` -root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local -``` - -``` -user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true -``` - -Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html): -``` -user:password@/dbname?sql_mode=TRADITIONAL -``` - -TCP via IPv6: -``` -user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci -``` - -TCP on a remote host, e.g. Amazon RDS: -``` -id:password@tcp(your-amazonaws-uri.com:3306)/dbname -``` - -Google Cloud SQL on App Engine: -``` -user:password@unix(/cloudsql/project-id:region-name:instance-name)/dbname -``` - -TCP using default port (3306) on localhost: -``` -user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped -``` - -Use the default protocol (tcp) and host (localhost:3306): -``` -user:password@/dbname -``` - -No Database preselected: -``` -user:password@/ -``` - - -### Connection pool and timeouts -The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. - -## `ColumnType` Support -This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. All Unsigned database type names will be returned `UNSIGNED ` with `INT`, `TINYINT`, `SMALLINT`, `MEDIUMINT`, `BIGINT`. - -## `context.Context` Support -Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. -See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. - - -### `LOAD DATA LOCAL INFILE` support -For this feature you need direct access to the package. Therefore you must change the import path (no `_`): -```go -import "github.com/go-sql-driver/mysql" -``` - -Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local)). - -To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. - -See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. - - -### `time.Time` support -The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program. - -However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical equivalent in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter. - -**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes). - - -### Unicode support -Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default. - -Other charsets / collations can be set using the [`charset`](#charset) or [`collation`](#collation) DSN parameter. - -- When only the `charset` is specified, the `SET NAMES ` query is sent and the server's default collation is used. -- When both the `charset` and `collation` are specified, the `SET NAMES COLLATE ` query is sent. -- When only the `collation` is specified, the collation is specified in the protocol handshake and the `SET NAMES` query is not sent. This can save one roundtrip, but note that the server may ignore the specified collation silently and use the server's default charset/collation instead. - -See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support. - -## Testing / Development -To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. - -Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated. -If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls). - -See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/.github/CONTRIBUTING.md) for details. - ---------------------------------------- - -## License -Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) - -Mozilla summarizes the license scope as follows: -> MPL: The copyleft applies to any files containing MPLed code. - - -That means: - * You can **use** the **unchanged** source code both in private and commercially. - * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0). - * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**. - -Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license. - -You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE). - -![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow") diff --git a/vendor/github.com/go-sql-driver/mysql/atomic_bool.go b/vendor/github.com/go-sql-driver/mysql/atomic_bool.go deleted file mode 100644 index 1b7e19f..0000000 --- a/vendor/github.com/go-sql-driver/mysql/atomic_bool.go +++ /dev/null @@ -1,19 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package. -// -// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. -//go:build go1.19 -// +build go1.19 - -package mysql - -import "sync/atomic" - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -type atomicBool = atomic.Bool diff --git a/vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go b/vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go deleted file mode 100644 index 2e9a7f0..0000000 --- a/vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go +++ /dev/null @@ -1,47 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package. -// -// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. -//go:build !go1.19 -// +build !go1.19 - -package mysql - -import "sync/atomic" - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -// atomicBool is an implementation of atomic.Bool for older version of Go. -// it is a wrapper around uint32 for usage as a boolean value with -// atomic access. -type atomicBool struct { - _ noCopy - value uint32 -} - -// Load returns whether the current boolean value is true -func (ab *atomicBool) Load() bool { - return atomic.LoadUint32(&ab.value) > 0 -} - -// Store sets the value of the bool regardless of the previous value -func (ab *atomicBool) Store(value bool) { - if value { - atomic.StoreUint32(&ab.value, 1) - } else { - atomic.StoreUint32(&ab.value, 0) - } -} - -// Swap sets the value of the bool and returns the old value. -func (ab *atomicBool) Swap(value bool) bool { - if value { - return atomic.SwapUint32(&ab.value, 1) > 0 - } - return atomic.SwapUint32(&ab.value, 0) > 0 -} diff --git a/vendor/github.com/go-sql-driver/mysql/auth.go b/vendor/github.com/go-sql-driver/mysql/auth.go deleted file mode 100644 index 74e1bd0..0000000 --- a/vendor/github.com/go-sql-driver/mysql/auth.go +++ /dev/null @@ -1,484 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "crypto/x509" - "encoding/pem" - "fmt" - "sync" - - "filippo.io/edwards25519" -) - -// server pub keys registry -var ( - serverPubKeyLock sync.RWMutex - serverPubKeyRegistry map[string]*rsa.PublicKey -) - -// RegisterServerPubKey registers a server RSA public key which can be used to -// send data in a secure manner to the server without receiving the public key -// in a potentially insecure way from the server first. -// Registered keys can afterwards be used adding serverPubKey= to the DSN. -// -// Note: The provided rsa.PublicKey instance is exclusively owned by the driver -// after registering it and may not be modified. -// -// data, err := os.ReadFile("mykey.pem") -// if err != nil { -// log.Fatal(err) -// } -// -// block, _ := pem.Decode(data) -// if block == nil || block.Type != "PUBLIC KEY" { -// log.Fatal("failed to decode PEM block containing public key") -// } -// -// pub, err := x509.ParsePKIXPublicKey(block.Bytes) -// if err != nil { -// log.Fatal(err) -// } -// -// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok { -// mysql.RegisterServerPubKey("mykey", rsaPubKey) -// } else { -// log.Fatal("not a RSA public key") -// } -func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) { - serverPubKeyLock.Lock() - if serverPubKeyRegistry == nil { - serverPubKeyRegistry = make(map[string]*rsa.PublicKey) - } - - serverPubKeyRegistry[name] = pubKey - serverPubKeyLock.Unlock() -} - -// DeregisterServerPubKey removes the public key registered with the given name. -func DeregisterServerPubKey(name string) { - serverPubKeyLock.Lock() - if serverPubKeyRegistry != nil { - delete(serverPubKeyRegistry, name) - } - serverPubKeyLock.Unlock() -} - -func getServerPubKey(name string) (pubKey *rsa.PublicKey) { - serverPubKeyLock.RLock() - if v, ok := serverPubKeyRegistry[name]; ok { - pubKey = v - } - serverPubKeyLock.RUnlock() - return -} - -// Hash password using pre 4.1 (old password) method -// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c -type myRnd struct { - seed1, seed2 uint32 -} - -const myRndMaxVal = 0x3FFFFFFF - -// Pseudo random number generator -func newMyRnd(seed1, seed2 uint32) *myRnd { - return &myRnd{ - seed1: seed1 % myRndMaxVal, - seed2: seed2 % myRndMaxVal, - } -} - -// Tested to be equivalent to MariaDB's floating point variant -// http://play.golang.org/p/QHvhd4qved -// http://play.golang.org/p/RG0q4ElWDx -func (r *myRnd) NextByte() byte { - r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal - r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal - - return byte(uint64(r.seed1) * 31 / myRndMaxVal) -} - -// Generate binary hash from byte string using insecure pre 4.1 method -func pwHash(password []byte) (result [2]uint32) { - var add uint32 = 7 - var tmp uint32 - - result[0] = 1345345333 - result[1] = 0x12345671 - - for _, c := range password { - // skip spaces and tabs in password - if c == ' ' || c == '\t' { - continue - } - - tmp = uint32(c) - result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8) - result[1] += (result[1] << 8) ^ result[0] - add += tmp - } - - // Remove sign bit (1<<31)-1) - result[0] &= 0x7FFFFFFF - result[1] &= 0x7FFFFFFF - - return -} - -// Hash password using insecure pre 4.1 method -func scrambleOldPassword(scramble []byte, password string) []byte { - scramble = scramble[:8] - - hashPw := pwHash([]byte(password)) - hashSc := pwHash(scramble) - - r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1]) - - var out [8]byte - for i := range out { - out[i] = r.NextByte() + 64 - } - - mask := r.NextByte() - for i := range out { - out[i] ^= mask - } - - return out[:] -} - -// Hash password using 4.1+ method (SHA1) -func scramblePassword(scramble []byte, password string) []byte { - if len(password) == 0 { - return nil - } - - // stage1Hash = SHA1(password) - crypt := sha1.New() - crypt.Write([]byte(password)) - stage1 := crypt.Sum(nil) - - // scrambleHash = SHA1(scramble + SHA1(stage1Hash)) - // inner Hash - crypt.Reset() - crypt.Write(stage1) - hash := crypt.Sum(nil) - - // outer Hash - crypt.Reset() - crypt.Write(scramble) - crypt.Write(hash) - scramble = crypt.Sum(nil) - - // token = scrambleHash XOR stage1Hash - for i := range scramble { - scramble[i] ^= stage1[i] - } - return scramble -} - -// Hash password using MySQL 8+ method (SHA256) -func scrambleSHA256Password(scramble []byte, password string) []byte { - if len(password) == 0 { - return nil - } - - // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble)) - - crypt := sha256.New() - crypt.Write([]byte(password)) - message1 := crypt.Sum(nil) - - crypt.Reset() - crypt.Write(message1) - message1Hash := crypt.Sum(nil) - - crypt.Reset() - crypt.Write(message1Hash) - crypt.Write(scramble) - message2 := crypt.Sum(nil) - - for i := range message1 { - message1[i] ^= message2[i] - } - - return message1 -} - -func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) { - plain := make([]byte, len(password)+1) - copy(plain, password) - for i := range plain { - j := i % len(seed) - plain[i] ^= seed[j] - } - sha1 := sha1.New() - return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil) -} - -// authEd25519 does ed25519 authentication used by MariaDB. -func authEd25519(scramble []byte, password string) ([]byte, error) { - // Derived from https://github.com/MariaDB/server/blob/d8e6bb00888b1f82c031938f4c8ac5d97f6874c3/plugin/auth_ed25519/ref10/sign.c - // Code style is from https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/crypto/ed25519/ed25519.go;l=207 - h := sha512.Sum512([]byte(password)) - - s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32]) - if err != nil { - return nil, err - } - A := (&edwards25519.Point{}).ScalarBaseMult(s) - - mh := sha512.New() - mh.Write(h[32:]) - mh.Write(scramble) - messageDigest := mh.Sum(nil) - r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest) - if err != nil { - return nil, err - } - - R := (&edwards25519.Point{}).ScalarBaseMult(r) - - kh := sha512.New() - kh.Write(R.Bytes()) - kh.Write(A.Bytes()) - kh.Write(scramble) - hramDigest := kh.Sum(nil) - k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest) - if err != nil { - return nil, err - } - - S := k.MultiplyAdd(k, s, r) - - return append(R.Bytes(), S.Bytes()...), nil -} - -func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error { - enc, err := encryptPassword(mc.cfg.Passwd, seed, pub) - if err != nil { - return err - } - return mc.writeAuthSwitchPacket(enc) -} - -func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) { - switch plugin { - case "caching_sha2_password": - authResp := scrambleSHA256Password(authData, mc.cfg.Passwd) - return authResp, nil - - case "mysql_old_password": - if !mc.cfg.AllowOldPasswords { - return nil, ErrOldPassword - } - if len(mc.cfg.Passwd) == 0 { - return nil, nil - } - // Note: there are edge cases where this should work but doesn't; - // this is currently "wontfix": - // https://github.com/go-sql-driver/mysql/issues/184 - authResp := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0) - return authResp, nil - - case "mysql_clear_password": - if !mc.cfg.AllowCleartextPasswords { - return nil, ErrCleartextPassword - } - // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html - // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html - return append([]byte(mc.cfg.Passwd), 0), nil - - case "mysql_native_password": - if !mc.cfg.AllowNativePasswords { - return nil, ErrNativePassword - } - // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html - // Native password authentication only need and will need 20-byte challenge. - authResp := scramblePassword(authData[:20], mc.cfg.Passwd) - return authResp, nil - - case "sha256_password": - if len(mc.cfg.Passwd) == 0 { - return []byte{0}, nil - } - // unlike caching_sha2_password, sha256_password does not accept - // cleartext password on unix transport. - if mc.cfg.TLS != nil { - // write cleartext auth packet - return append([]byte(mc.cfg.Passwd), 0), nil - } - - pubKey := mc.cfg.pubKey - if pubKey == nil { - // request public key from server - return []byte{1}, nil - } - - // encrypted password - enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) - return enc, err - - case "client_ed25519": - if len(authData) != 32 { - return nil, ErrMalformPkt - } - return authEd25519(authData, mc.cfg.Passwd) - - default: - mc.log("unknown auth plugin:", plugin) - return nil, ErrUnknownPlugin - } -} - -func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error { - // Read Result Packet - authData, newPlugin, err := mc.readAuthResult() - if err != nil { - return err - } - - // handle auth plugin switch, if requested - if newPlugin != "" { - // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is - // sent and we have to keep using the cipher sent in the init packet. - if authData == nil { - authData = oldAuthData - } else { - // copy data from read buffer to owned slice - copy(oldAuthData, authData) - } - - plugin = newPlugin - - authResp, err := mc.auth(authData, plugin) - if err != nil { - return err - } - if err = mc.writeAuthSwitchPacket(authResp); err != nil { - return err - } - - // Read Result Packet - authData, newPlugin, err = mc.readAuthResult() - if err != nil { - return err - } - - // Do not allow to change the auth plugin more than once - if newPlugin != "" { - return ErrMalformPkt - } - } - - switch plugin { - - // https://dev.mysql.com/blog-archive/preparing-your-community-connector-for-mysql-8-part-2-sha256/ - case "caching_sha2_password": - switch len(authData) { - case 0: - return nil // auth successful - case 1: - switch authData[0] { - case cachingSha2PasswordFastAuthSuccess: - if err = mc.resultUnchanged().readResultOK(); err == nil { - return nil // auth successful - } - - case cachingSha2PasswordPerformFullAuthentication: - if mc.cfg.TLS != nil || mc.cfg.Net == "unix" { - // write cleartext auth packet - err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0)) - if err != nil { - return err - } - } else { - pubKey := mc.cfg.pubKey - if pubKey == nil { - // request public key from server - data, err := mc.buf.takeSmallBuffer(4 + 1) - if err != nil { - return err - } - data[4] = cachingSha2PasswordRequestPublicKey - err = mc.writePacket(data) - if err != nil { - return err - } - - if data, err = mc.readPacket(); err != nil { - return err - } - - if data[0] != iAuthMoreData { - return fmt.Errorf("unexpected resp from server for caching_sha2_password, perform full authentication") - } - - // parse public key - block, rest := pem.Decode(data[1:]) - if block == nil { - return fmt.Errorf("no pem data found, data: %s", rest) - } - pkix, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return err - } - pubKey = pkix.(*rsa.PublicKey) - } - - // send encrypted password - err = mc.sendEncryptedPassword(oldAuthData, pubKey) - if err != nil { - return err - } - } - return mc.resultUnchanged().readResultOK() - - default: - return ErrMalformPkt - } - default: - return ErrMalformPkt - } - - case "sha256_password": - switch len(authData) { - case 0: - return nil // auth successful - default: - block, _ := pem.Decode(authData) - if block == nil { - return fmt.Errorf("no Pem data found, data: %s", authData) - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return err - } - - // send encrypted password - err = mc.sendEncryptedPassword(oldAuthData, pub.(*rsa.PublicKey)) - if err != nil { - return err - } - return mc.resultUnchanged().readResultOK() - } - - default: - return nil // auth successful - } - - return err -} diff --git a/vendor/github.com/go-sql-driver/mysql/buffer.go b/vendor/github.com/go-sql-driver/mysql/buffer.go deleted file mode 100644 index 0774c5c..0000000 --- a/vendor/github.com/go-sql-driver/mysql/buffer.go +++ /dev/null @@ -1,182 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "io" - "net" - "time" -) - -const defaultBufSize = 4096 -const maxCachedBufSize = 256 * 1024 - -// A buffer which is used for both reading and writing. -// This is possible since communication on each connection is synchronous. -// In other words, we can't write and read simultaneously on the same connection. -// The buffer is similar to bufio.Reader / Writer but zero-copy-ish -// Also highly optimized for this particular use case. -// This buffer is backed by two byte slices in a double-buffering scheme -type buffer struct { - buf []byte // buf is a byte buffer who's length and capacity are equal. - nc net.Conn - idx int - length int - timeout time.Duration - dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer - flipcnt uint // flipccnt is the current buffer counter for double-buffering -} - -// newBuffer allocates and returns a new buffer. -func newBuffer(nc net.Conn) buffer { - fg := make([]byte, defaultBufSize) - return buffer{ - buf: fg, - nc: nc, - dbuf: [2][]byte{fg, nil}, - } -} - -// flip replaces the active buffer with the background buffer -// this is a delayed flip that simply increases the buffer counter; -// the actual flip will be performed the next time we call `buffer.fill` -func (b *buffer) flip() { - b.flipcnt += 1 -} - -// fill reads into the buffer until at least _need_ bytes are in it -func (b *buffer) fill(need int) error { - n := b.length - // fill data into its double-buffering target: if we've called - // flip on this buffer, we'll be copying to the background buffer, - // and then filling it with network data; otherwise we'll just move - // the contents of the current buffer to the front before filling it - dest := b.dbuf[b.flipcnt&1] - - // grow buffer if necessary to fit the whole packet. - if need > len(dest) { - // Round up to the next multiple of the default size - dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) - - // if the allocated buffer is not too large, move it to backing storage - // to prevent extra allocations on applications that perform large reads - if len(dest) <= maxCachedBufSize { - b.dbuf[b.flipcnt&1] = dest - } - } - - // if we're filling the fg buffer, move the existing data to the start of it. - // if we're filling the bg buffer, copy over the data - if n > 0 { - copy(dest[:n], b.buf[b.idx:]) - } - - b.buf = dest - b.idx = 0 - - for { - if b.timeout > 0 { - if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil { - return err - } - } - - nn, err := b.nc.Read(b.buf[n:]) - n += nn - - switch err { - case nil: - if n < need { - continue - } - b.length = n - return nil - - case io.EOF: - if n >= need { - b.length = n - return nil - } - return io.ErrUnexpectedEOF - - default: - return err - } - } -} - -// returns next N bytes from buffer. -// The returned slice is only guaranteed to be valid until the next read -func (b *buffer) readNext(need int) ([]byte, error) { - if b.length < need { - // refill - if err := b.fill(need); err != nil { - return nil, err - } - } - - offset := b.idx - b.idx += need - b.length -= need - return b.buf[offset:b.idx], nil -} - -// takeBuffer returns a buffer with the requested size. -// If possible, a slice from the existing buffer is returned. -// Otherwise a bigger buffer is made. -// Only one buffer (total) can be used at a time. -func (b *buffer) takeBuffer(length int) ([]byte, error) { - if b.length > 0 { - return nil, ErrBusyBuffer - } - - // test (cheap) general case first - if length <= cap(b.buf) { - return b.buf[:length], nil - } - - if length < maxPacketSize { - b.buf = make([]byte, length) - return b.buf, nil - } - - // buffer is larger than we want to store. - return make([]byte, length), nil -} - -// takeSmallBuffer is shortcut which can be used if length is -// known to be smaller than defaultBufSize. -// Only one buffer (total) can be used at a time. -func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { - if b.length > 0 { - return nil, ErrBusyBuffer - } - return b.buf[:length], nil -} - -// takeCompleteBuffer returns the complete existing buffer. -// This can be used if the necessary buffer size is unknown. -// cap and len of the returned buffer will be equal. -// Only one buffer (total) can be used at a time. -func (b *buffer) takeCompleteBuffer() ([]byte, error) { - if b.length > 0 { - return nil, ErrBusyBuffer - } - return b.buf, nil -} - -// store stores buf, an updated buffer, if its suitable to do so. -func (b *buffer) store(buf []byte) error { - if b.length > 0 { - return ErrBusyBuffer - } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) { - b.buf = buf[:cap(buf)] - } - return nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/collations.go b/vendor/github.com/go-sql-driver/mysql/collations.go deleted file mode 100644 index 1cdf97b..0000000 --- a/vendor/github.com/go-sql-driver/mysql/collations.go +++ /dev/null @@ -1,266 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -const defaultCollation = "utf8mb4_general_ci" -const binaryCollationID = 63 - -// A list of available collations mapped to the internal ID. -// To update this map use the following MySQL query: -// -// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS WHERE ID<256 ORDER BY ID -// -// Handshake packet have only 1 byte for collation_id. So we can't use collations with ID > 255. -// -// ucs2, utf16, and utf32 can't be used for connection charset. -// https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset -// They are commented out to reduce this map. -var collations = map[string]byte{ - "big5_chinese_ci": 1, - "latin2_czech_cs": 2, - "dec8_swedish_ci": 3, - "cp850_general_ci": 4, - "latin1_german1_ci": 5, - "hp8_english_ci": 6, - "koi8r_general_ci": 7, - "latin1_swedish_ci": 8, - "latin2_general_ci": 9, - "swe7_swedish_ci": 10, - "ascii_general_ci": 11, - "ujis_japanese_ci": 12, - "sjis_japanese_ci": 13, - "cp1251_bulgarian_ci": 14, - "latin1_danish_ci": 15, - "hebrew_general_ci": 16, - "tis620_thai_ci": 18, - "euckr_korean_ci": 19, - "latin7_estonian_cs": 20, - "latin2_hungarian_ci": 21, - "koi8u_general_ci": 22, - "cp1251_ukrainian_ci": 23, - "gb2312_chinese_ci": 24, - "greek_general_ci": 25, - "cp1250_general_ci": 26, - "latin2_croatian_ci": 27, - "gbk_chinese_ci": 28, - "cp1257_lithuanian_ci": 29, - "latin5_turkish_ci": 30, - "latin1_german2_ci": 31, - "armscii8_general_ci": 32, - "utf8_general_ci": 33, - "cp1250_czech_cs": 34, - //"ucs2_general_ci": 35, - "cp866_general_ci": 36, - "keybcs2_general_ci": 37, - "macce_general_ci": 38, - "macroman_general_ci": 39, - "cp852_general_ci": 40, - "latin7_general_ci": 41, - "latin7_general_cs": 42, - "macce_bin": 43, - "cp1250_croatian_ci": 44, - "utf8mb4_general_ci": 45, - "utf8mb4_bin": 46, - "latin1_bin": 47, - "latin1_general_ci": 48, - "latin1_general_cs": 49, - "cp1251_bin": 50, - "cp1251_general_ci": 51, - "cp1251_general_cs": 52, - "macroman_bin": 53, - //"utf16_general_ci": 54, - //"utf16_bin": 55, - //"utf16le_general_ci": 56, - "cp1256_general_ci": 57, - "cp1257_bin": 58, - "cp1257_general_ci": 59, - //"utf32_general_ci": 60, - //"utf32_bin": 61, - //"utf16le_bin": 62, - "binary": 63, - "armscii8_bin": 64, - "ascii_bin": 65, - "cp1250_bin": 66, - "cp1256_bin": 67, - "cp866_bin": 68, - "dec8_bin": 69, - "greek_bin": 70, - "hebrew_bin": 71, - "hp8_bin": 72, - "keybcs2_bin": 73, - "koi8r_bin": 74, - "koi8u_bin": 75, - "utf8_tolower_ci": 76, - "latin2_bin": 77, - "latin5_bin": 78, - "latin7_bin": 79, - "cp850_bin": 80, - "cp852_bin": 81, - "swe7_bin": 82, - "utf8_bin": 83, - "big5_bin": 84, - "euckr_bin": 85, - "gb2312_bin": 86, - "gbk_bin": 87, - "sjis_bin": 88, - "tis620_bin": 89, - //"ucs2_bin": 90, - "ujis_bin": 91, - "geostd8_general_ci": 92, - "geostd8_bin": 93, - "latin1_spanish_ci": 94, - "cp932_japanese_ci": 95, - "cp932_bin": 96, - "eucjpms_japanese_ci": 97, - "eucjpms_bin": 98, - "cp1250_polish_ci": 99, - //"utf16_unicode_ci": 101, - //"utf16_icelandic_ci": 102, - //"utf16_latvian_ci": 103, - //"utf16_romanian_ci": 104, - //"utf16_slovenian_ci": 105, - //"utf16_polish_ci": 106, - //"utf16_estonian_ci": 107, - //"utf16_spanish_ci": 108, - //"utf16_swedish_ci": 109, - //"utf16_turkish_ci": 110, - //"utf16_czech_ci": 111, - //"utf16_danish_ci": 112, - //"utf16_lithuanian_ci": 113, - //"utf16_slovak_ci": 114, - //"utf16_spanish2_ci": 115, - //"utf16_roman_ci": 116, - //"utf16_persian_ci": 117, - //"utf16_esperanto_ci": 118, - //"utf16_hungarian_ci": 119, - //"utf16_sinhala_ci": 120, - //"utf16_german2_ci": 121, - //"utf16_croatian_ci": 122, - //"utf16_unicode_520_ci": 123, - //"utf16_vietnamese_ci": 124, - //"ucs2_unicode_ci": 128, - //"ucs2_icelandic_ci": 129, - //"ucs2_latvian_ci": 130, - //"ucs2_romanian_ci": 131, - //"ucs2_slovenian_ci": 132, - //"ucs2_polish_ci": 133, - //"ucs2_estonian_ci": 134, - //"ucs2_spanish_ci": 135, - //"ucs2_swedish_ci": 136, - //"ucs2_turkish_ci": 137, - //"ucs2_czech_ci": 138, - //"ucs2_danish_ci": 139, - //"ucs2_lithuanian_ci": 140, - //"ucs2_slovak_ci": 141, - //"ucs2_spanish2_ci": 142, - //"ucs2_roman_ci": 143, - //"ucs2_persian_ci": 144, - //"ucs2_esperanto_ci": 145, - //"ucs2_hungarian_ci": 146, - //"ucs2_sinhala_ci": 147, - //"ucs2_german2_ci": 148, - //"ucs2_croatian_ci": 149, - //"ucs2_unicode_520_ci": 150, - //"ucs2_vietnamese_ci": 151, - //"ucs2_general_mysql500_ci": 159, - //"utf32_unicode_ci": 160, - //"utf32_icelandic_ci": 161, - //"utf32_latvian_ci": 162, - //"utf32_romanian_ci": 163, - //"utf32_slovenian_ci": 164, - //"utf32_polish_ci": 165, - //"utf32_estonian_ci": 166, - //"utf32_spanish_ci": 167, - //"utf32_swedish_ci": 168, - //"utf32_turkish_ci": 169, - //"utf32_czech_ci": 170, - //"utf32_danish_ci": 171, - //"utf32_lithuanian_ci": 172, - //"utf32_slovak_ci": 173, - //"utf32_spanish2_ci": 174, - //"utf32_roman_ci": 175, - //"utf32_persian_ci": 176, - //"utf32_esperanto_ci": 177, - //"utf32_hungarian_ci": 178, - //"utf32_sinhala_ci": 179, - //"utf32_german2_ci": 180, - //"utf32_croatian_ci": 181, - //"utf32_unicode_520_ci": 182, - //"utf32_vietnamese_ci": 183, - "utf8_unicode_ci": 192, - "utf8_icelandic_ci": 193, - "utf8_latvian_ci": 194, - "utf8_romanian_ci": 195, - "utf8_slovenian_ci": 196, - "utf8_polish_ci": 197, - "utf8_estonian_ci": 198, - "utf8_spanish_ci": 199, - "utf8_swedish_ci": 200, - "utf8_turkish_ci": 201, - "utf8_czech_ci": 202, - "utf8_danish_ci": 203, - "utf8_lithuanian_ci": 204, - "utf8_slovak_ci": 205, - "utf8_spanish2_ci": 206, - "utf8_roman_ci": 207, - "utf8_persian_ci": 208, - "utf8_esperanto_ci": 209, - "utf8_hungarian_ci": 210, - "utf8_sinhala_ci": 211, - "utf8_german2_ci": 212, - "utf8_croatian_ci": 213, - "utf8_unicode_520_ci": 214, - "utf8_vietnamese_ci": 215, - "utf8_general_mysql500_ci": 223, - "utf8mb4_unicode_ci": 224, - "utf8mb4_icelandic_ci": 225, - "utf8mb4_latvian_ci": 226, - "utf8mb4_romanian_ci": 227, - "utf8mb4_slovenian_ci": 228, - "utf8mb4_polish_ci": 229, - "utf8mb4_estonian_ci": 230, - "utf8mb4_spanish_ci": 231, - "utf8mb4_swedish_ci": 232, - "utf8mb4_turkish_ci": 233, - "utf8mb4_czech_ci": 234, - "utf8mb4_danish_ci": 235, - "utf8mb4_lithuanian_ci": 236, - "utf8mb4_slovak_ci": 237, - "utf8mb4_spanish2_ci": 238, - "utf8mb4_roman_ci": 239, - "utf8mb4_persian_ci": 240, - "utf8mb4_esperanto_ci": 241, - "utf8mb4_hungarian_ci": 242, - "utf8mb4_sinhala_ci": 243, - "utf8mb4_german2_ci": 244, - "utf8mb4_croatian_ci": 245, - "utf8mb4_unicode_520_ci": 246, - "utf8mb4_vietnamese_ci": 247, - "gb18030_chinese_ci": 248, - "gb18030_bin": 249, - "gb18030_unicode_520_ci": 250, - "utf8mb4_0900_ai_ci": 255, -} - -// A denylist of collations which is unsafe to interpolate parameters. -// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes. -var unsafeCollations = map[string]bool{ - "big5_chinese_ci": true, - "sjis_japanese_ci": true, - "gbk_chinese_ci": true, - "big5_bin": true, - "gb2312_bin": true, - "gbk_bin": true, - "sjis_bin": true, - "cp932_japanese_ci": true, - "cp932_bin": true, - "gb18030_chinese_ci": true, - "gb18030_bin": true, - "gb18030_unicode_520_ci": true, -} diff --git a/vendor/github.com/go-sql-driver/mysql/conncheck.go b/vendor/github.com/go-sql-driver/mysql/conncheck.go deleted file mode 100644 index 0ea7217..0000000 --- a/vendor/github.com/go-sql-driver/mysql/conncheck.go +++ /dev/null @@ -1,55 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -//go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || illumos -// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos - -package mysql - -import ( - "errors" - "io" - "net" - "syscall" -) - -var errUnexpectedRead = errors.New("unexpected read from socket") - -func connCheck(conn net.Conn) error { - var sysErr error - - sysConn, ok := conn.(syscall.Conn) - if !ok { - return nil - } - rawConn, err := sysConn.SyscallConn() - if err != nil { - return err - } - - err = rawConn.Read(func(fd uintptr) bool { - var buf [1]byte - n, err := syscall.Read(int(fd), buf[:]) - switch { - case n == 0 && err == nil: - sysErr = io.EOF - case n > 0: - sysErr = errUnexpectedRead - case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK: - sysErr = nil - default: - sysErr = err - } - return true - }) - if err != nil { - return err - } - - return sysErr -} diff --git a/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go b/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go deleted file mode 100644 index a56c138..0000000 --- a/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go +++ /dev/null @@ -1,18 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -//go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !illumos -// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos - -package mysql - -import "net" - -func connCheck(conn net.Conn) error { - return nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/connection.go b/vendor/github.com/go-sql-driver/mysql/connection.go deleted file mode 100644 index eff978d..0000000 --- a/vendor/github.com/go-sql-driver/mysql/connection.go +++ /dev/null @@ -1,688 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "context" - "database/sql" - "database/sql/driver" - "encoding/json" - "io" - "net" - "strconv" - "strings" - "time" -) - -type mysqlConn struct { - buf buffer - netConn net.Conn - rawConn net.Conn // underlying connection when netConn is TLS connection. - result mysqlResult // managed by clearResult() and handleOkPacket(). - cfg *Config - connector *connector - maxAllowedPacket int - maxWriteSize int - writeTimeout time.Duration - flags clientFlag - status statusFlag - sequence uint8 - parseTime bool - - // for context support (Go 1.8+) - watching bool - watcher chan<- context.Context - closech chan struct{} - finished chan<- struct{} - canceled atomicError // set non-nil if conn is canceled - closed atomicBool // set when conn is closed, before closech is closed -} - -// Helper function to call per-connection logger. -func (mc *mysqlConn) log(v ...any) { - mc.cfg.Logger.Print(v...) -} - -// Handles parameters set in DSN after the connection is established -func (mc *mysqlConn) handleParams() (err error) { - var cmdSet strings.Builder - - for param, val := range mc.cfg.Params { - switch param { - // Charset: character_set_connection, character_set_client, character_set_results - case "charset": - charsets := strings.Split(val, ",") - for _, cs := range charsets { - // ignore errors here - a charset may not exist - if mc.cfg.Collation != "" { - err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation) - } else { - err = mc.exec("SET NAMES " + cs) - } - if err == nil { - break - } - } - if err != nil { - return - } - - // Other system vars accumulated in a single SET command - default: - if cmdSet.Len() == 0 { - // Heuristic: 29 chars for each other key=value to reduce reallocations - cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1)) - cmdSet.WriteString("SET ") - } else { - cmdSet.WriteString(", ") - } - cmdSet.WriteString(param) - cmdSet.WriteString(" = ") - cmdSet.WriteString(val) - } - } - - if cmdSet.Len() > 0 { - err = mc.exec(cmdSet.String()) - if err != nil { - return - } - } - - return -} - -func (mc *mysqlConn) markBadConn(err error) error { - if mc == nil { - return err - } - if err != errBadConnNoWrite { - return err - } - return driver.ErrBadConn -} - -func (mc *mysqlConn) Begin() (driver.Tx, error) { - return mc.begin(false) -} - -func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { - if mc.closed.Load() { - mc.log(ErrInvalidConn) - return nil, driver.ErrBadConn - } - var q string - if readOnly { - q = "START TRANSACTION READ ONLY" - } else { - q = "START TRANSACTION" - } - err := mc.exec(q) - if err == nil { - return &mysqlTx{mc}, err - } - return nil, mc.markBadConn(err) -} - -func (mc *mysqlConn) Close() (err error) { - // Makes Close idempotent - if !mc.closed.Load() { - err = mc.writeCommandPacket(comQuit) - } - - mc.cleanup() - mc.clearResult() - return -} - -// Closes the network connection and unsets internal variables. Do not call this -// function after successfully authentication, call Close instead. This function -// is called before auth or on auth failure because MySQL will have already -// closed the network connection. -func (mc *mysqlConn) cleanup() { - if mc.closed.Swap(true) { - return - } - - // Makes cleanup idempotent - close(mc.closech) - conn := mc.rawConn - if conn == nil { - return - } - if err := conn.Close(); err != nil { - mc.log(err) - } - // This function can be called from multiple goroutines. - // So we can not mc.clearResult() here. - // Caller should do it if they are in safe goroutine. -} - -func (mc *mysqlConn) error() error { - if mc.closed.Load() { - if err := mc.canceled.Value(); err != nil { - return err - } - return ErrInvalidConn - } - return nil -} - -func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { - if mc.closed.Load() { - mc.log(ErrInvalidConn) - return nil, driver.ErrBadConn - } - // Send command - err := mc.writeCommandPacketStr(comStmtPrepare, query) - if err != nil { - // STMT_PREPARE is safe to retry. So we can return ErrBadConn here. - mc.log(err) - return nil, driver.ErrBadConn - } - - stmt := &mysqlStmt{ - mc: mc, - } - - // Read Result - columnCount, err := stmt.readPrepareResultPacket() - if err == nil { - if stmt.paramCount > 0 { - if err = mc.readUntilEOF(); err != nil { - return nil, err - } - } - - if columnCount > 0 { - err = mc.readUntilEOF() - } - } - - return stmt, err -} - -func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { - // Number of ? should be same to len(args) - if strings.Count(query, "?") != len(args) { - return "", driver.ErrSkip - } - - buf, err := mc.buf.takeCompleteBuffer() - if err != nil { - // can not take the buffer. Something must be wrong with the connection - mc.log(err) - return "", ErrInvalidConn - } - buf = buf[:0] - argPos := 0 - - for i := 0; i < len(query); i++ { - q := strings.IndexByte(query[i:], '?') - if q == -1 { - buf = append(buf, query[i:]...) - break - } - buf = append(buf, query[i:i+q]...) - i += q - - arg := args[argPos] - argPos++ - - if arg == nil { - buf = append(buf, "NULL"...) - continue - } - - switch v := arg.(type) { - case int64: - buf = strconv.AppendInt(buf, v, 10) - case uint64: - // Handle uint64 explicitly because our custom ConvertValue emits unsigned values - buf = strconv.AppendUint(buf, v, 10) - case float64: - buf = strconv.AppendFloat(buf, v, 'g', -1, 64) - case bool: - if v { - buf = append(buf, '1') - } else { - buf = append(buf, '0') - } - case time.Time: - if v.IsZero() { - buf = append(buf, "'0000-00-00'"...) - } else { - buf = append(buf, '\'') - buf, err = appendDateTime(buf, v.In(mc.cfg.Loc), mc.cfg.timeTruncate) - if err != nil { - return "", err - } - buf = append(buf, '\'') - } - case json.RawMessage: - buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) - } else { - buf = escapeBytesQuotes(buf, v) - } - buf = append(buf, '\'') - case []byte: - if v == nil { - buf = append(buf, "NULL"...) - } else { - buf = append(buf, "_binary'"...) - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) - } else { - buf = escapeBytesQuotes(buf, v) - } - buf = append(buf, '\'') - } - case string: - buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeStringBackslash(buf, v) - } else { - buf = escapeStringQuotes(buf, v) - } - buf = append(buf, '\'') - default: - return "", driver.ErrSkip - } - - if len(buf)+4 > mc.maxAllowedPacket { - return "", driver.ErrSkip - } - } - if argPos != len(args) { - return "", driver.ErrSkip - } - return string(buf), nil -} - -func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { - if mc.closed.Load() { - mc.log(ErrInvalidConn) - return nil, driver.ErrBadConn - } - if len(args) != 0 { - if !mc.cfg.InterpolateParams { - return nil, driver.ErrSkip - } - // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement - prepared, err := mc.interpolateParams(query, args) - if err != nil { - return nil, err - } - query = prepared - } - - err := mc.exec(query) - if err == nil { - copied := mc.result - return &copied, err - } - return nil, mc.markBadConn(err) -} - -// Internal function to execute commands -func (mc *mysqlConn) exec(query string) error { - handleOk := mc.clearResult() - // Send command - if err := mc.writeCommandPacketStr(comQuery, query); err != nil { - return mc.markBadConn(err) - } - - // Read Result - resLen, err := handleOk.readResultSetHeaderPacket() - if err != nil { - return err - } - - if resLen > 0 { - // columns - if err := mc.readUntilEOF(); err != nil { - return err - } - - // rows - if err := mc.readUntilEOF(); err != nil { - return err - } - } - - return handleOk.discardResults() -} - -func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { - return mc.query(query, args) -} - -func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { - handleOk := mc.clearResult() - - if mc.closed.Load() { - mc.log(ErrInvalidConn) - return nil, driver.ErrBadConn - } - if len(args) != 0 { - if !mc.cfg.InterpolateParams { - return nil, driver.ErrSkip - } - // try client-side prepare to reduce roundtrip - prepared, err := mc.interpolateParams(query, args) - if err != nil { - return nil, err - } - query = prepared - } - // Send command - err := mc.writeCommandPacketStr(comQuery, query) - if err == nil { - // Read Result - var resLen int - resLen, err = handleOk.readResultSetHeaderPacket() - if err == nil { - rows := new(textRows) - rows.mc = mc - - if resLen == 0 { - rows.rs.done = true - - switch err := rows.NextResultSet(); err { - case nil, io.EOF: - return rows, nil - default: - return nil, err - } - } - - // Columns - rows.rs.columns, err = mc.readColumns(resLen) - return rows, err - } - } - return nil, mc.markBadConn(err) -} - -// Gets the value of the given MySQL System Variable -// The returned byte slice is only valid until the next read -func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { - // Send command - handleOk := mc.clearResult() - if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { - return nil, err - } - - // Read Result - resLen, err := handleOk.readResultSetHeaderPacket() - if err == nil { - rows := new(textRows) - rows.mc = mc - rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}} - - if resLen > 0 { - // Columns - if err := mc.readUntilEOF(); err != nil { - return nil, err - } - } - - dest := make([]driver.Value, resLen) - if err = rows.readRow(dest); err == nil { - return dest[0].([]byte), mc.readUntilEOF() - } - } - return nil, err -} - -// finish is called when the query has canceled. -func (mc *mysqlConn) cancel(err error) { - mc.canceled.Set(err) - mc.cleanup() -} - -// finish is called when the query has succeeded. -func (mc *mysqlConn) finish() { - if !mc.watching || mc.finished == nil { - return - } - select { - case mc.finished <- struct{}{}: - mc.watching = false - case <-mc.closech: - } -} - -// Ping implements driver.Pinger interface -func (mc *mysqlConn) Ping(ctx context.Context) (err error) { - if mc.closed.Load() { - mc.log(ErrInvalidConn) - return driver.ErrBadConn - } - - if err = mc.watchCancel(ctx); err != nil { - return - } - defer mc.finish() - - handleOk := mc.clearResult() - if err = mc.writeCommandPacket(comPing); err != nil { - return mc.markBadConn(err) - } - - return handleOk.readResultOK() -} - -// BeginTx implements driver.ConnBeginTx interface -func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - if mc.closed.Load() { - return nil, driver.ErrBadConn - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - defer mc.finish() - - if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { - level, err := mapIsolationLevel(opts.Isolation) - if err != nil { - return nil, err - } - err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) - if err != nil { - return nil, err - } - } - - return mc.begin(opts.ReadOnly) -} - -func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - - rows, err := mc.query(query, dargs) - if err != nil { - mc.finish() - return nil, err - } - rows.finish = mc.finish - return rows, err -} - -func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - defer mc.finish() - - return mc.Exec(query, dargs) -} - -func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - - stmt, err := mc.Prepare(query) - mc.finish() - if err != nil { - return nil, err - } - - select { - default: - case <-ctx.Done(): - stmt.Close() - return nil, ctx.Err() - } - return stmt, nil -} - -func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := stmt.mc.watchCancel(ctx); err != nil { - return nil, err - } - - rows, err := stmt.query(dargs) - if err != nil { - stmt.mc.finish() - return nil, err - } - rows.finish = stmt.mc.finish - return rows, err -} - -func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := stmt.mc.watchCancel(ctx); err != nil { - return nil, err - } - defer stmt.mc.finish() - - return stmt.Exec(dargs) -} - -func (mc *mysqlConn) watchCancel(ctx context.Context) error { - if mc.watching { - // Reach here if canceled, - // so the connection is already invalid - mc.cleanup() - return nil - } - // When ctx is already cancelled, don't watch it. - if err := ctx.Err(); err != nil { - return err - } - // When ctx is not cancellable, don't watch it. - if ctx.Done() == nil { - return nil - } - // When watcher is not alive, can't watch it. - if mc.watcher == nil { - return nil - } - - mc.watching = true - mc.watcher <- ctx - return nil -} - -func (mc *mysqlConn) startWatcher() { - watcher := make(chan context.Context, 1) - mc.watcher = watcher - finished := make(chan struct{}) - mc.finished = finished - go func() { - for { - var ctx context.Context - select { - case ctx = <-watcher: - case <-mc.closech: - return - } - - select { - case <-ctx.Done(): - mc.cancel(ctx.Err()) - case <-finished: - case <-mc.closech: - return - } - } - }() -} - -func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { - nv.Value, err = converter{}.ConvertValue(nv.Value) - return -} - -// ResetSession implements driver.SessionResetter. -// (From Go 1.10) -func (mc *mysqlConn) ResetSession(ctx context.Context) error { - if mc.closed.Load() { - return driver.ErrBadConn - } - - // Perform a stale connection check. We only perform this check for - // the first query on a connection that has been checked out of the - // connection pool: a fresh connection from the pool is more likely - // to be stale, and it has not performed any previous writes that - // could cause data corruption, so it's safe to return ErrBadConn - // if the check fails. - if mc.cfg.CheckConnLiveness { - conn := mc.netConn - if mc.rawConn != nil { - conn = mc.rawConn - } - var err error - if mc.cfg.ReadTimeout != 0 { - err = conn.SetReadDeadline(time.Now().Add(mc.cfg.ReadTimeout)) - } - if err == nil { - err = connCheck(conn) - } - if err != nil { - mc.log("closing bad idle connection: ", err) - return driver.ErrBadConn - } - } - - return nil -} - -// IsValid implements driver.Validator interface -// (From Go 1.15) -func (mc *mysqlConn) IsValid() bool { - return !mc.closed.Load() -} diff --git a/vendor/github.com/go-sql-driver/mysql/connector.go b/vendor/github.com/go-sql-driver/mysql/connector.go deleted file mode 100644 index b670775..0000000 --- a/vendor/github.com/go-sql-driver/mysql/connector.go +++ /dev/null @@ -1,197 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "context" - "database/sql/driver" - "net" - "os" - "strconv" - "strings" -) - -type connector struct { - cfg *Config // immutable private copy. - encodedAttributes string // Encoded connection attributes. -} - -func encodeConnectionAttributes(cfg *Config) string { - connAttrsBuf := make([]byte, 0) - - // default connection attributes - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientName) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientNameValue) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOS) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOSValue) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatform) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatformValue) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPid) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, strconv.Itoa(os.Getpid())) - serverHost, _, _ := net.SplitHostPort(cfg.Addr) - if serverHost != "" { - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrServerHost) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, serverHost) - } - - // user-defined connection attributes - for _, connAttr := range strings.Split(cfg.ConnectionAttributes, ",") { - k, v, found := strings.Cut(connAttr, ":") - if !found { - continue - } - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, k) - connAttrsBuf = appendLengthEncodedString(connAttrsBuf, v) - } - - return string(connAttrsBuf) -} - -func newConnector(cfg *Config) *connector { - encodedAttributes := encodeConnectionAttributes(cfg) - return &connector{ - cfg: cfg, - encodedAttributes: encodedAttributes, - } -} - -// Connect implements driver.Connector interface. -// Connect returns a connection to the database. -func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { - var err error - - // Invoke beforeConnect if present, with a copy of the configuration - cfg := c.cfg - if c.cfg.beforeConnect != nil { - cfg = c.cfg.Clone() - err = c.cfg.beforeConnect(ctx, cfg) - if err != nil { - return nil, err - } - } - - // New mysqlConn - mc := &mysqlConn{ - maxAllowedPacket: maxPacketSize, - maxWriteSize: maxPacketSize - 1, - closech: make(chan struct{}), - cfg: cfg, - connector: c, - } - mc.parseTime = mc.cfg.ParseTime - - // Connect to Server - dialsLock.RLock() - dial, ok := dials[mc.cfg.Net] - dialsLock.RUnlock() - if ok { - dctx := ctx - if mc.cfg.Timeout > 0 { - var cancel context.CancelFunc - dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout) - defer cancel() - } - mc.netConn, err = dial(dctx, mc.cfg.Addr) - } else { - nd := net.Dialer{Timeout: mc.cfg.Timeout} - mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr) - } - if err != nil { - return nil, err - } - mc.rawConn = mc.netConn - - // Enable TCP Keepalives on TCP connections - if tc, ok := mc.netConn.(*net.TCPConn); ok { - if err := tc.SetKeepAlive(true); err != nil { - c.cfg.Logger.Print(err) - } - } - - // Call startWatcher for context support (From Go 1.8) - mc.startWatcher() - if err := mc.watchCancel(ctx); err != nil { - mc.cleanup() - return nil, err - } - defer mc.finish() - - mc.buf = newBuffer(mc.netConn) - - // Set I/O timeouts - mc.buf.timeout = mc.cfg.ReadTimeout - mc.writeTimeout = mc.cfg.WriteTimeout - - // Reading Handshake Initialization Packet - authData, plugin, err := mc.readHandshakePacket() - if err != nil { - mc.cleanup() - return nil, err - } - - if plugin == "" { - plugin = defaultAuthPlugin - } - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - // try the default auth plugin, if using the requested plugin failed - c.cfg.Logger.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) - plugin = defaultAuthPlugin - authResp, err = mc.auth(authData, plugin) - if err != nil { - mc.cleanup() - return nil, err - } - } - if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil { - mc.cleanup() - return nil, err - } - - // Handle response to auth packet, switch methods if possible - if err = mc.handleAuthResult(authData, plugin); err != nil { - // Authentication failed and MySQL has already closed the connection - // (https://dev.mysql.com/doc/internals/en/authentication-fails.html). - // Do not send COM_QUIT, just cleanup and return the error. - mc.cleanup() - return nil, err - } - - if mc.cfg.MaxAllowedPacket > 0 { - mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket - } else { - // Get max allowed packet size - maxap, err := mc.getSystemVar("max_allowed_packet") - if err != nil { - mc.Close() - return nil, err - } - mc.maxAllowedPacket = stringToInt(maxap) - 1 - } - if mc.maxAllowedPacket < maxPacketSize { - mc.maxWriteSize = mc.maxAllowedPacket - } - - // Handle DSN Params - err = mc.handleParams() - if err != nil { - mc.Close() - return nil, err - } - - return mc, nil -} - -// Driver implements driver.Connector interface. -// Driver returns &MySQLDriver{}. -func (c *connector) Driver() driver.Driver { - return &MySQLDriver{} -} diff --git a/vendor/github.com/go-sql-driver/mysql/const.go b/vendor/github.com/go-sql-driver/mysql/const.go deleted file mode 100644 index 22526e0..0000000 --- a/vendor/github.com/go-sql-driver/mysql/const.go +++ /dev/null @@ -1,187 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import "runtime" - -const ( - defaultAuthPlugin = "mysql_native_password" - defaultMaxAllowedPacket = 64 << 20 // 64 MiB. See https://github.com/go-sql-driver/mysql/issues/1355 - minProtocolVersion = 10 - maxPacketSize = 1<<24 - 1 - timeFormat = "2006-01-02 15:04:05.999999" - - // Connection attributes - // See https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html#performance-schema-connection-attributes-available - connAttrClientName = "_client_name" - connAttrClientNameValue = "Go-MySQL-Driver" - connAttrOS = "_os" - connAttrOSValue = runtime.GOOS - connAttrPlatform = "_platform" - connAttrPlatformValue = runtime.GOARCH - connAttrPid = "_pid" - connAttrServerHost = "_server_host" -) - -// MySQL constants documentation: -// http://dev.mysql.com/doc/internals/en/client-server-protocol.html - -const ( - iOK byte = 0x00 - iAuthMoreData byte = 0x01 - iLocalInFile byte = 0xfb - iEOF byte = 0xfe - iERR byte = 0xff -) - -// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags -type clientFlag uint32 - -const ( - clientLongPassword clientFlag = 1 << iota - clientFoundRows - clientLongFlag - clientConnectWithDB - clientNoSchema - clientCompress - clientODBC - clientLocalFiles - clientIgnoreSpace - clientProtocol41 - clientInteractive - clientSSL - clientIgnoreSIGPIPE - clientTransactions - clientReserved - clientSecureConn - clientMultiStatements - clientMultiResults - clientPSMultiResults - clientPluginAuth - clientConnectAttrs - clientPluginAuthLenEncClientData - clientCanHandleExpiredPasswords - clientSessionTrack - clientDeprecateEOF -) - -const ( - comQuit byte = iota + 1 - comInitDB - comQuery - comFieldList - comCreateDB - comDropDB - comRefresh - comShutdown - comStatistics - comProcessInfo - comConnect - comProcessKill - comDebug - comPing - comTime - comDelayedInsert - comChangeUser - comBinlogDump - comTableDump - comConnectOut - comRegisterSlave - comStmtPrepare - comStmtExecute - comStmtSendLongData - comStmtClose - comStmtReset - comSetOption - comStmtFetch -) - -// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType -type fieldType byte - -const ( - fieldTypeDecimal fieldType = iota - fieldTypeTiny - fieldTypeShort - fieldTypeLong - fieldTypeFloat - fieldTypeDouble - fieldTypeNULL - fieldTypeTimestamp - fieldTypeLongLong - fieldTypeInt24 - fieldTypeDate - fieldTypeTime - fieldTypeDateTime - fieldTypeYear - fieldTypeNewDate - fieldTypeVarChar - fieldTypeBit -) -const ( - fieldTypeJSON fieldType = iota + 0xf5 - fieldTypeNewDecimal - fieldTypeEnum - fieldTypeSet - fieldTypeTinyBLOB - fieldTypeMediumBLOB - fieldTypeLongBLOB - fieldTypeBLOB - fieldTypeVarString - fieldTypeString - fieldTypeGeometry -) - -type fieldFlag uint16 - -const ( - flagNotNULL fieldFlag = 1 << iota - flagPriKey - flagUniqueKey - flagMultipleKey - flagBLOB - flagUnsigned - flagZeroFill - flagBinary - flagEnum - flagAutoIncrement - flagTimestamp - flagSet - flagUnknown1 - flagUnknown2 - flagUnknown3 - flagUnknown4 -) - -// http://dev.mysql.com/doc/internals/en/status-flags.html -type statusFlag uint16 - -const ( - statusInTrans statusFlag = 1 << iota - statusInAutocommit - statusReserved // Not in documentation - statusMoreResultsExists - statusNoGoodIndexUsed - statusNoIndexUsed - statusCursorExists - statusLastRowSent - statusDbDropped - statusNoBackslashEscapes - statusMetadataChanged - statusQueryWasSlow - statusPsOutParams - statusInTransReadonly - statusSessionStateChanged -) - -const ( - cachingSha2PasswordRequestPublicKey = 2 - cachingSha2PasswordFastAuthSuccess = 3 - cachingSha2PasswordPerformFullAuthentication = 4 -) diff --git a/vendor/github.com/go-sql-driver/mysql/driver.go b/vendor/github.com/go-sql-driver/mysql/driver.go deleted file mode 100644 index 105316b..0000000 --- a/vendor/github.com/go-sql-driver/mysql/driver.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// Package mysql provides a MySQL driver for Go's database/sql package. -// -// The driver should be used via the database/sql package: -// -// import "database/sql" -// import _ "github.com/go-sql-driver/mysql" -// -// db, err := sql.Open("mysql", "user:password@/dbname") -// -// See https://github.com/go-sql-driver/mysql#usage for details -package mysql - -import ( - "context" - "database/sql" - "database/sql/driver" - "net" - "sync" -) - -// MySQLDriver is exported to make the driver directly accessible. -// In general the driver is used via the database/sql package. -type MySQLDriver struct{} - -// DialFunc is a function which can be used to establish the network connection. -// Custom dial functions must be registered with RegisterDial -// -// Deprecated: users should register a DialContextFunc instead -type DialFunc func(addr string) (net.Conn, error) - -// DialContextFunc is a function which can be used to establish the network connection. -// Custom dial functions must be registered with RegisterDialContext -type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error) - -var ( - dialsLock sync.RWMutex - dials map[string]DialContextFunc -) - -// RegisterDialContext registers a custom dial function. It can then be used by the -// network address mynet(addr), where mynet is the registered new network. -// The current context for the connection and its address is passed to the dial function. -func RegisterDialContext(net string, dial DialContextFunc) { - dialsLock.Lock() - defer dialsLock.Unlock() - if dials == nil { - dials = make(map[string]DialContextFunc) - } - dials[net] = dial -} - -// DeregisterDialContext removes the custom dial function registered with the given net. -func DeregisterDialContext(net string) { - dialsLock.Lock() - defer dialsLock.Unlock() - if dials != nil { - delete(dials, net) - } -} - -// RegisterDial registers a custom dial function. It can then be used by the -// network address mynet(addr), where mynet is the registered new network. -// addr is passed as a parameter to the dial function. -// -// Deprecated: users should call RegisterDialContext instead -func RegisterDial(network string, dial DialFunc) { - RegisterDialContext(network, func(_ context.Context, addr string) (net.Conn, error) { - return dial(addr) - }) -} - -// Open new Connection. -// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how -// the DSN string is formatted -func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { - cfg, err := ParseDSN(dsn) - if err != nil { - return nil, err - } - c := newConnector(cfg) - return c.Connect(context.Background()) -} - -// This variable can be replaced with -ldflags like below: -// go build "-ldflags=-X github.com/go-sql-driver/mysql.driverName=custom" -var driverName = "mysql" - -func init() { - if driverName != "" { - sql.Register(driverName, &MySQLDriver{}) - } -} - -// NewConnector returns new driver.Connector. -func NewConnector(cfg *Config) (driver.Connector, error) { - cfg = cfg.Clone() - // normalize the contents of cfg so calls to NewConnector have the same - // behavior as MySQLDriver.OpenConnector - if err := cfg.normalize(); err != nil { - return nil, err - } - return newConnector(cfg), nil -} - -// OpenConnector implements driver.DriverContext. -func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) { - cfg, err := ParseDSN(dsn) - if err != nil { - return nil, err - } - return newConnector(cfg), nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/dsn.go b/vendor/github.com/go-sql-driver/mysql/dsn.go deleted file mode 100644 index 65f5a02..0000000 --- a/vendor/github.com/go-sql-driver/mysql/dsn.go +++ /dev/null @@ -1,653 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "context" - "crypto/rsa" - "crypto/tls" - "errors" - "fmt" - "math/big" - "net" - "net/url" - "sort" - "strconv" - "strings" - "time" -) - -var ( - errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?") - errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)") - errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name") - errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") -) - -// Config is a configuration parsed from a DSN string. -// If a new Config is created instead of being parsed from a DSN string, -// the NewConfig function should be used, which sets default values. -type Config struct { - // non boolean fields - - User string // Username - Passwd string // Password (requires User) - Net string // Network (e.g. "tcp", "tcp6", "unix". default: "tcp") - Addr string // Address (default: "127.0.0.1:3306" for "tcp" and "/tmp/mysql.sock" for "unix") - DBName string // Database name - Params map[string]string // Connection parameters - ConnectionAttributes string // Connection Attributes, comma-delimited string of user-defined "key:value" pairs - Collation string // Connection collation - Loc *time.Location // Location for time.Time values - MaxAllowedPacket int // Max packet size allowed - ServerPubKey string // Server public key name - TLSConfig string // TLS configuration name - TLS *tls.Config // TLS configuration, its priority is higher than TLSConfig - Timeout time.Duration // Dial timeout - ReadTimeout time.Duration // I/O read timeout - WriteTimeout time.Duration // I/O write timeout - Logger Logger // Logger - - // boolean fields - - AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE - AllowCleartextPasswords bool // Allows the cleartext client side plugin - AllowFallbackToPlaintext bool // Allows fallback to unencrypted connection if server does not support TLS - AllowNativePasswords bool // Allows the native password authentication method - AllowOldPasswords bool // Allows the old insecure password method - CheckConnLiveness bool // Check connections for liveness before using them - ClientFoundRows bool // Return number of matching rows instead of rows changed - ColumnsWithAlias bool // Prepend table alias to column names - InterpolateParams bool // Interpolate placeholders into query string - MultiStatements bool // Allow multiple statements in one query - ParseTime bool // Parse time values to time.Time - RejectReadOnly bool // Reject read-only connections - - // unexported fields. new options should be come here - - beforeConnect func(context.Context, *Config) error // Invoked before a connection is established - pubKey *rsa.PublicKey // Server public key - timeTruncate time.Duration // Truncate time.Time values to the specified duration -} - -// Functional Options Pattern -// https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis -type Option func(*Config) error - -// NewConfig creates a new Config and sets default values. -func NewConfig() *Config { - cfg := &Config{ - Loc: time.UTC, - MaxAllowedPacket: defaultMaxAllowedPacket, - Logger: defaultLogger, - AllowNativePasswords: true, - CheckConnLiveness: true, - } - - return cfg -} - -// Apply applies the given options to the Config object. -func (c *Config) Apply(opts ...Option) error { - for _, opt := range opts { - err := opt(c) - if err != nil { - return err - } - } - return nil -} - -// TimeTruncate sets the time duration to truncate time.Time values in -// query parameters. -func TimeTruncate(d time.Duration) Option { - return func(cfg *Config) error { - cfg.timeTruncate = d - return nil - } -} - -// BeforeConnect sets the function to be invoked before a connection is established. -func BeforeConnect(fn func(context.Context, *Config) error) Option { - return func(cfg *Config) error { - cfg.beforeConnect = fn - return nil - } -} - -func (cfg *Config) Clone() *Config { - cp := *cfg - if cp.TLS != nil { - cp.TLS = cfg.TLS.Clone() - } - if len(cp.Params) > 0 { - cp.Params = make(map[string]string, len(cfg.Params)) - for k, v := range cfg.Params { - cp.Params[k] = v - } - } - if cfg.pubKey != nil { - cp.pubKey = &rsa.PublicKey{ - N: new(big.Int).Set(cfg.pubKey.N), - E: cfg.pubKey.E, - } - } - return &cp -} - -func (cfg *Config) normalize() error { - if cfg.InterpolateParams && cfg.Collation != "" && unsafeCollations[cfg.Collation] { - return errInvalidDSNUnsafeCollation - } - - // Set default network if empty - if cfg.Net == "" { - cfg.Net = "tcp" - } - - // Set default address if empty - if cfg.Addr == "" { - switch cfg.Net { - case "tcp": - cfg.Addr = "127.0.0.1:3306" - case "unix": - cfg.Addr = "/tmp/mysql.sock" - default: - return errors.New("default addr for network '" + cfg.Net + "' unknown") - } - } else if cfg.Net == "tcp" { - cfg.Addr = ensureHavePort(cfg.Addr) - } - - if cfg.TLS == nil { - switch cfg.TLSConfig { - case "false", "": - // don't set anything - case "true": - cfg.TLS = &tls.Config{} - case "skip-verify": - cfg.TLS = &tls.Config{InsecureSkipVerify: true} - case "preferred": - cfg.TLS = &tls.Config{InsecureSkipVerify: true} - cfg.AllowFallbackToPlaintext = true - default: - cfg.TLS = getTLSConfigClone(cfg.TLSConfig) - if cfg.TLS == nil { - return errors.New("invalid value / unknown config name: " + cfg.TLSConfig) - } - } - } - - if cfg.TLS != nil && cfg.TLS.ServerName == "" && !cfg.TLS.InsecureSkipVerify { - host, _, err := net.SplitHostPort(cfg.Addr) - if err == nil { - cfg.TLS.ServerName = host - } - } - - if cfg.ServerPubKey != "" { - cfg.pubKey = getServerPubKey(cfg.ServerPubKey) - if cfg.pubKey == nil { - return errors.New("invalid value / unknown server pub key name: " + cfg.ServerPubKey) - } - } - - if cfg.Logger == nil { - cfg.Logger = defaultLogger - } - - return nil -} - -func writeDSNParam(buf *bytes.Buffer, hasParam *bool, name, value string) { - buf.Grow(1 + len(name) + 1 + len(value)) - if !*hasParam { - *hasParam = true - buf.WriteByte('?') - } else { - buf.WriteByte('&') - } - buf.WriteString(name) - buf.WriteByte('=') - buf.WriteString(value) -} - -// FormatDSN formats the given Config into a DSN string which can be passed to -// the driver. -// -// Note: use [NewConnector] and [database/sql.OpenDB] to open a connection from a [*Config]. -func (cfg *Config) FormatDSN() string { - var buf bytes.Buffer - - // [username[:password]@] - if len(cfg.User) > 0 { - buf.WriteString(cfg.User) - if len(cfg.Passwd) > 0 { - buf.WriteByte(':') - buf.WriteString(cfg.Passwd) - } - buf.WriteByte('@') - } - - // [protocol[(address)]] - if len(cfg.Net) > 0 { - buf.WriteString(cfg.Net) - if len(cfg.Addr) > 0 { - buf.WriteByte('(') - buf.WriteString(cfg.Addr) - buf.WriteByte(')') - } - } - - // /dbname - buf.WriteByte('/') - buf.WriteString(url.PathEscape(cfg.DBName)) - - // [?param1=value1&...¶mN=valueN] - hasParam := false - - if cfg.AllowAllFiles { - hasParam = true - buf.WriteString("?allowAllFiles=true") - } - - if cfg.AllowCleartextPasswords { - writeDSNParam(&buf, &hasParam, "allowCleartextPasswords", "true") - } - - if cfg.AllowFallbackToPlaintext { - writeDSNParam(&buf, &hasParam, "allowFallbackToPlaintext", "true") - } - - if !cfg.AllowNativePasswords { - writeDSNParam(&buf, &hasParam, "allowNativePasswords", "false") - } - - if cfg.AllowOldPasswords { - writeDSNParam(&buf, &hasParam, "allowOldPasswords", "true") - } - - if !cfg.CheckConnLiveness { - writeDSNParam(&buf, &hasParam, "checkConnLiveness", "false") - } - - if cfg.ClientFoundRows { - writeDSNParam(&buf, &hasParam, "clientFoundRows", "true") - } - - if col := cfg.Collation; col != "" { - writeDSNParam(&buf, &hasParam, "collation", col) - } - - if cfg.ColumnsWithAlias { - writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true") - } - - if cfg.InterpolateParams { - writeDSNParam(&buf, &hasParam, "interpolateParams", "true") - } - - if cfg.Loc != time.UTC && cfg.Loc != nil { - writeDSNParam(&buf, &hasParam, "loc", url.QueryEscape(cfg.Loc.String())) - } - - if cfg.MultiStatements { - writeDSNParam(&buf, &hasParam, "multiStatements", "true") - } - - if cfg.ParseTime { - writeDSNParam(&buf, &hasParam, "parseTime", "true") - } - - if cfg.timeTruncate > 0 { - writeDSNParam(&buf, &hasParam, "timeTruncate", cfg.timeTruncate.String()) - } - - if cfg.ReadTimeout > 0 { - writeDSNParam(&buf, &hasParam, "readTimeout", cfg.ReadTimeout.String()) - } - - if cfg.RejectReadOnly { - writeDSNParam(&buf, &hasParam, "rejectReadOnly", "true") - } - - if len(cfg.ServerPubKey) > 0 { - writeDSNParam(&buf, &hasParam, "serverPubKey", url.QueryEscape(cfg.ServerPubKey)) - } - - if cfg.Timeout > 0 { - writeDSNParam(&buf, &hasParam, "timeout", cfg.Timeout.String()) - } - - if len(cfg.TLSConfig) > 0 { - writeDSNParam(&buf, &hasParam, "tls", url.QueryEscape(cfg.TLSConfig)) - } - - if cfg.WriteTimeout > 0 { - writeDSNParam(&buf, &hasParam, "writeTimeout", cfg.WriteTimeout.String()) - } - - if cfg.MaxAllowedPacket != defaultMaxAllowedPacket { - writeDSNParam(&buf, &hasParam, "maxAllowedPacket", strconv.Itoa(cfg.MaxAllowedPacket)) - } - - // other params - if cfg.Params != nil { - var params []string - for param := range cfg.Params { - params = append(params, param) - } - sort.Strings(params) - for _, param := range params { - writeDSNParam(&buf, &hasParam, param, url.QueryEscape(cfg.Params[param])) - } - } - - return buf.String() -} - -// ParseDSN parses the DSN string to a Config -func ParseDSN(dsn string) (cfg *Config, err error) { - // New config with some default values - cfg = NewConfig() - - // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] - // Find the last '/' (since the password or the net addr might contain a '/') - foundSlash := false - for i := len(dsn) - 1; i >= 0; i-- { - if dsn[i] == '/' { - foundSlash = true - var j, k int - - // left part is empty if i <= 0 - if i > 0 { - // [username[:password]@][protocol[(address)]] - // Find the last '@' in dsn[:i] - for j = i; j >= 0; j-- { - if dsn[j] == '@' { - // username[:password] - // Find the first ':' in dsn[:j] - for k = 0; k < j; k++ { - if dsn[k] == ':' { - cfg.Passwd = dsn[k+1 : j] - break - } - } - cfg.User = dsn[:k] - - break - } - } - - // [protocol[(address)]] - // Find the first '(' in dsn[j+1:i] - for k = j + 1; k < i; k++ { - if dsn[k] == '(' { - // dsn[i-1] must be == ')' if an address is specified - if dsn[i-1] != ')' { - if strings.ContainsRune(dsn[k+1:i], ')') { - return nil, errInvalidDSNUnescaped - } - return nil, errInvalidDSNAddr - } - cfg.Addr = dsn[k+1 : i-1] - break - } - } - cfg.Net = dsn[j+1 : k] - } - - // dbname[?param1=value1&...¶mN=valueN] - // Find the first '?' in dsn[i+1:] - for j = i + 1; j < len(dsn); j++ { - if dsn[j] == '?' { - if err = parseDSNParams(cfg, dsn[j+1:]); err != nil { - return - } - break - } - } - - dbname := dsn[i+1 : j] - if cfg.DBName, err = url.PathUnescape(dbname); err != nil { - return nil, fmt.Errorf("invalid dbname %q: %w", dbname, err) - } - - break - } - } - - if !foundSlash && len(dsn) > 0 { - return nil, errInvalidDSNNoSlash - } - - if err = cfg.normalize(); err != nil { - return nil, err - } - return -} - -// parseDSNParams parses the DSN "query string" -// Values must be url.QueryEscape'ed -func parseDSNParams(cfg *Config, params string) (err error) { - for _, v := range strings.Split(params, "&") { - key, value, found := strings.Cut(v, "=") - if !found { - continue - } - - // cfg params - switch key { - // Disable INFILE allowlist / enable all files - case "allowAllFiles": - var isBool bool - cfg.AllowAllFiles, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Use cleartext authentication mode (MySQL 5.5.10+) - case "allowCleartextPasswords": - var isBool bool - cfg.AllowCleartextPasswords, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Allow fallback to unencrypted connection if server does not support TLS - case "allowFallbackToPlaintext": - var isBool bool - cfg.AllowFallbackToPlaintext, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Use native password authentication - case "allowNativePasswords": - var isBool bool - cfg.AllowNativePasswords, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Use old authentication mode (pre MySQL 4.1) - case "allowOldPasswords": - var isBool bool - cfg.AllowOldPasswords, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Check connections for Liveness before using them - case "checkConnLiveness": - var isBool bool - cfg.CheckConnLiveness, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Switch "rowsAffected" mode - case "clientFoundRows": - var isBool bool - cfg.ClientFoundRows, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Collation - case "collation": - cfg.Collation = value - - case "columnsWithAlias": - var isBool bool - cfg.ColumnsWithAlias, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Compression - case "compress": - return errors.New("compression not implemented yet") - - // Enable client side placeholder substitution - case "interpolateParams": - var isBool bool - cfg.InterpolateParams, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Time Location - case "loc": - if value, err = url.QueryUnescape(value); err != nil { - return - } - cfg.Loc, err = time.LoadLocation(value) - if err != nil { - return - } - - // multiple statements in one query - case "multiStatements": - var isBool bool - cfg.MultiStatements, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // time.Time parsing - case "parseTime": - var isBool bool - cfg.ParseTime, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // time.Time truncation - case "timeTruncate": - cfg.timeTruncate, err = time.ParseDuration(value) - if err != nil { - return fmt.Errorf("invalid timeTruncate value: %v, error: %w", value, err) - } - - // I/O read Timeout - case "readTimeout": - cfg.ReadTimeout, err = time.ParseDuration(value) - if err != nil { - return - } - - // Reject read-only connections - case "rejectReadOnly": - var isBool bool - cfg.RejectReadOnly, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Server public key - case "serverPubKey": - name, err := url.QueryUnescape(value) - if err != nil { - return fmt.Errorf("invalid value for server pub key name: %v", err) - } - cfg.ServerPubKey = name - - // Strict mode - case "strict": - panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode") - - // Dial Timeout - case "timeout": - cfg.Timeout, err = time.ParseDuration(value) - if err != nil { - return - } - - // TLS-Encryption - case "tls": - boolValue, isBool := readBool(value) - if isBool { - if boolValue { - cfg.TLSConfig = "true" - } else { - cfg.TLSConfig = "false" - } - } else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" { - cfg.TLSConfig = vl - } else { - name, err := url.QueryUnescape(value) - if err != nil { - return fmt.Errorf("invalid value for TLS config name: %v", err) - } - cfg.TLSConfig = name - } - - // I/O write Timeout - case "writeTimeout": - cfg.WriteTimeout, err = time.ParseDuration(value) - if err != nil { - return - } - case "maxAllowedPacket": - cfg.MaxAllowedPacket, err = strconv.Atoi(value) - if err != nil { - return - } - - // Connection attributes - case "connectionAttributes": - connectionAttributes, err := url.QueryUnescape(value) - if err != nil { - return fmt.Errorf("invalid connectionAttributes value: %v", err) - } - cfg.ConnectionAttributes = connectionAttributes - - default: - // lazy init - if cfg.Params == nil { - cfg.Params = make(map[string]string) - } - - if cfg.Params[key], err = url.QueryUnescape(value); err != nil { - return - } - } - } - - return -} - -func ensureHavePort(addr string) string { - if _, _, err := net.SplitHostPort(addr); err != nil { - return net.JoinHostPort(addr, "3306") - } - return addr -} diff --git a/vendor/github.com/go-sql-driver/mysql/errors.go b/vendor/github.com/go-sql-driver/mysql/errors.go deleted file mode 100644 index a7ef889..0000000 --- a/vendor/github.com/go-sql-driver/mysql/errors.go +++ /dev/null @@ -1,83 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "errors" - "fmt" - "log" - "os" -) - -// Various errors the driver might return. Can change between driver versions. -var ( - ErrInvalidConn = errors.New("invalid connection") - ErrMalformPkt = errors.New("malformed packet") - ErrNoTLS = errors.New("TLS requested but server does not support TLS") - ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN") - ErrNativePassword = errors.New("this user requires mysql native password authentication") - ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords") - ErrUnknownPlugin = errors.New("this authentication plugin is not supported") - ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+") - ErrPktSync = errors.New("commands out of sync. You can't run this command now") - ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") - ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the `Config.MaxAllowedPacket`") - ErrBusyBuffer = errors.New("busy buffer") - - // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. - // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn - // to trigger a resend. - // See https://github.com/go-sql-driver/mysql/pull/302 - errBadConnNoWrite = errors.New("bad connection") -) - -var defaultLogger = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) - -// Logger is used to log critical error messages. -type Logger interface { - Print(v ...any) -} - -// NopLogger is a nop implementation of the Logger interface. -type NopLogger struct{} - -// Print implements Logger interface. -func (nl *NopLogger) Print(_ ...any) {} - -// SetLogger is used to set the default logger for critical errors. -// The initial logger is os.Stderr. -func SetLogger(logger Logger) error { - if logger == nil { - return errors.New("logger is nil") - } - defaultLogger = logger - return nil -} - -// MySQLError is an error type which represents a single MySQL error -type MySQLError struct { - Number uint16 - SQLState [5]byte - Message string -} - -func (me *MySQLError) Error() string { - if me.SQLState != [5]byte{} { - return fmt.Sprintf("Error %d (%s): %s", me.Number, me.SQLState, me.Message) - } - - return fmt.Sprintf("Error %d: %s", me.Number, me.Message) -} - -func (me *MySQLError) Is(err error) bool { - if merr, ok := err.(*MySQLError); ok { - return merr.Number == me.Number - } - return false -} diff --git a/vendor/github.com/go-sql-driver/mysql/fields.go b/vendor/github.com/go-sql-driver/mysql/fields.go deleted file mode 100644 index 2860842..0000000 --- a/vendor/github.com/go-sql-driver/mysql/fields.go +++ /dev/null @@ -1,222 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql" - "reflect" -) - -func (mf *mysqlField) typeDatabaseName() string { - switch mf.fieldType { - case fieldTypeBit: - return "BIT" - case fieldTypeBLOB: - if mf.charSet != binaryCollationID { - return "TEXT" - } - return "BLOB" - case fieldTypeDate: - return "DATE" - case fieldTypeDateTime: - return "DATETIME" - case fieldTypeDecimal: - return "DECIMAL" - case fieldTypeDouble: - return "DOUBLE" - case fieldTypeEnum: - return "ENUM" - case fieldTypeFloat: - return "FLOAT" - case fieldTypeGeometry: - return "GEOMETRY" - case fieldTypeInt24: - if mf.flags&flagUnsigned != 0 { - return "UNSIGNED MEDIUMINT" - } - return "MEDIUMINT" - case fieldTypeJSON: - return "JSON" - case fieldTypeLong: - if mf.flags&flagUnsigned != 0 { - return "UNSIGNED INT" - } - return "INT" - case fieldTypeLongBLOB: - if mf.charSet != binaryCollationID { - return "LONGTEXT" - } - return "LONGBLOB" - case fieldTypeLongLong: - if mf.flags&flagUnsigned != 0 { - return "UNSIGNED BIGINT" - } - return "BIGINT" - case fieldTypeMediumBLOB: - if mf.charSet != binaryCollationID { - return "MEDIUMTEXT" - } - return "MEDIUMBLOB" - case fieldTypeNewDate: - return "DATE" - case fieldTypeNewDecimal: - return "DECIMAL" - case fieldTypeNULL: - return "NULL" - case fieldTypeSet: - return "SET" - case fieldTypeShort: - if mf.flags&flagUnsigned != 0 { - return "UNSIGNED SMALLINT" - } - return "SMALLINT" - case fieldTypeString: - if mf.flags&flagEnum != 0 { - return "ENUM" - } else if mf.flags&flagSet != 0 { - return "SET" - } - if mf.charSet == binaryCollationID { - return "BINARY" - } - return "CHAR" - case fieldTypeTime: - return "TIME" - case fieldTypeTimestamp: - return "TIMESTAMP" - case fieldTypeTiny: - if mf.flags&flagUnsigned != 0 { - return "UNSIGNED TINYINT" - } - return "TINYINT" - case fieldTypeTinyBLOB: - if mf.charSet != binaryCollationID { - return "TINYTEXT" - } - return "TINYBLOB" - case fieldTypeVarChar: - if mf.charSet == binaryCollationID { - return "VARBINARY" - } - return "VARCHAR" - case fieldTypeVarString: - if mf.charSet == binaryCollationID { - return "VARBINARY" - } - return "VARCHAR" - case fieldTypeYear: - return "YEAR" - default: - return "" - } -} - -var ( - scanTypeFloat32 = reflect.TypeOf(float32(0)) - scanTypeFloat64 = reflect.TypeOf(float64(0)) - scanTypeInt8 = reflect.TypeOf(int8(0)) - scanTypeInt16 = reflect.TypeOf(int16(0)) - scanTypeInt32 = reflect.TypeOf(int32(0)) - scanTypeInt64 = reflect.TypeOf(int64(0)) - scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) - scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) - scanTypeNullTime = reflect.TypeOf(sql.NullTime{}) - scanTypeUint8 = reflect.TypeOf(uint8(0)) - scanTypeUint16 = reflect.TypeOf(uint16(0)) - scanTypeUint32 = reflect.TypeOf(uint32(0)) - scanTypeUint64 = reflect.TypeOf(uint64(0)) - scanTypeString = reflect.TypeOf("") - scanTypeNullString = reflect.TypeOf(sql.NullString{}) - scanTypeBytes = reflect.TypeOf([]byte{}) - scanTypeUnknown = reflect.TypeOf(new(any)) -) - -type mysqlField struct { - tableName string - name string - length uint32 - flags fieldFlag - fieldType fieldType - decimals byte - charSet uint8 -} - -func (mf *mysqlField) scanType() reflect.Type { - switch mf.fieldType { - case fieldTypeTiny: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint8 - } - return scanTypeInt8 - } - return scanTypeNullInt - - case fieldTypeShort, fieldTypeYear: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint16 - } - return scanTypeInt16 - } - return scanTypeNullInt - - case fieldTypeInt24, fieldTypeLong: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint32 - } - return scanTypeInt32 - } - return scanTypeNullInt - - case fieldTypeLongLong: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint64 - } - return scanTypeInt64 - } - return scanTypeNullInt - - case fieldTypeFloat: - if mf.flags&flagNotNULL != 0 { - return scanTypeFloat32 - } - return scanTypeNullFloat - - case fieldTypeDouble: - if mf.flags&flagNotNULL != 0 { - return scanTypeFloat64 - } - return scanTypeNullFloat - - case fieldTypeBit, fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, - fieldTypeBLOB, fieldTypeVarString, fieldTypeString, fieldTypeGeometry: - if mf.charSet == binaryCollationID { - return scanTypeBytes - } - fallthrough - case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, - fieldTypeEnum, fieldTypeSet, fieldTypeJSON, fieldTypeTime: - if mf.flags&flagNotNULL != 0 { - return scanTypeString - } - return scanTypeNullString - - case fieldTypeDate, fieldTypeNewDate, - fieldTypeTimestamp, fieldTypeDateTime: - // NullTime is always returned for more consistent behavior as it can - // handle both cases of parseTime regardless if the field is nullable. - return scanTypeNullTime - - default: - return scanTypeUnknown - } -} diff --git a/vendor/github.com/go-sql-driver/mysql/infile.go b/vendor/github.com/go-sql-driver/mysql/infile.go deleted file mode 100644 index 0c8af9f..0000000 --- a/vendor/github.com/go-sql-driver/mysql/infile.go +++ /dev/null @@ -1,182 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "fmt" - "io" - "os" - "strings" - "sync" -) - -var ( - fileRegister map[string]bool - fileRegisterLock sync.RWMutex - readerRegister map[string]func() io.Reader - readerRegisterLock sync.RWMutex -) - -// RegisterLocalFile adds the given file to the file allowlist, -// so that it can be used by "LOAD DATA LOCAL INFILE ". -// Alternatively you can allow the use of all local files with -// the DSN parameter 'allowAllFiles=true' -// -// filePath := "/home/gopher/data.csv" -// mysql.RegisterLocalFile(filePath) -// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo") -// if err != nil { -// ... -func RegisterLocalFile(filePath string) { - fileRegisterLock.Lock() - // lazy map init - if fileRegister == nil { - fileRegister = make(map[string]bool) - } - - fileRegister[strings.Trim(filePath, `"`)] = true - fileRegisterLock.Unlock() -} - -// DeregisterLocalFile removes the given filepath from the allowlist. -func DeregisterLocalFile(filePath string) { - fileRegisterLock.Lock() - delete(fileRegister, strings.Trim(filePath, `"`)) - fileRegisterLock.Unlock() -} - -// RegisterReaderHandler registers a handler function which is used -// to receive a io.Reader. -// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::". -// If the handler returns a io.ReadCloser Close() is called when the -// request is finished. -// -// mysql.RegisterReaderHandler("data", func() io.Reader { -// var csvReader io.Reader // Some Reader that returns CSV data -// ... // Open Reader here -// return csvReader -// }) -// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo") -// if err != nil { -// ... -func RegisterReaderHandler(name string, handler func() io.Reader) { - readerRegisterLock.Lock() - // lazy map init - if readerRegister == nil { - readerRegister = make(map[string]func() io.Reader) - } - - readerRegister[name] = handler - readerRegisterLock.Unlock() -} - -// DeregisterReaderHandler removes the ReaderHandler function with -// the given name from the registry. -func DeregisterReaderHandler(name string) { - readerRegisterLock.Lock() - delete(readerRegister, name) - readerRegisterLock.Unlock() -} - -func deferredClose(err *error, closer io.Closer) { - closeErr := closer.Close() - if *err == nil { - *err = closeErr - } -} - -const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP - -func (mc *okHandler) handleInFileRequest(name string) (err error) { - var rdr io.Reader - var data []byte - packetSize := defaultPacketSize - if mc.maxWriteSize < packetSize { - packetSize = mc.maxWriteSize - } - - if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader - // The server might return an an absolute path. See issue #355. - name = name[idx+8:] - - readerRegisterLock.RLock() - handler, inMap := readerRegister[name] - readerRegisterLock.RUnlock() - - if inMap { - rdr = handler() - if rdr != nil { - if cl, ok := rdr.(io.Closer); ok { - defer deferredClose(&err, cl) - } - } else { - err = fmt.Errorf("reader '%s' is ", name) - } - } else { - err = fmt.Errorf("reader '%s' is not registered", name) - } - } else { // File - name = strings.Trim(name, `"`) - fileRegisterLock.RLock() - fr := fileRegister[name] - fileRegisterLock.RUnlock() - if mc.cfg.AllowAllFiles || fr { - var file *os.File - var fi os.FileInfo - - if file, err = os.Open(name); err == nil { - defer deferredClose(&err, file) - - // get file size - if fi, err = file.Stat(); err == nil { - rdr = file - if fileSize := int(fi.Size()); fileSize < packetSize { - packetSize = fileSize - } - } - } - } else { - err = fmt.Errorf("local file '%s' is not registered", name) - } - } - - // send content packets - // if packetSize == 0, the Reader contains no data - if err == nil && packetSize > 0 { - data := make([]byte, 4+packetSize) - var n int - for err == nil { - n, err = rdr.Read(data[4:]) - if n > 0 { - if ioErr := mc.conn().writePacket(data[:4+n]); ioErr != nil { - return ioErr - } - } - } - if err == io.EOF { - err = nil - } - } - - // send empty packet (termination) - if data == nil { - data = make([]byte, 4) - } - if ioErr := mc.conn().writePacket(data[:4]); ioErr != nil { - return ioErr - } - - // read OK packet - if err == nil { - return mc.readResultOK() - } - - mc.conn().readPacket() - return err -} diff --git a/vendor/github.com/go-sql-driver/mysql/nulltime.go b/vendor/github.com/go-sql-driver/mysql/nulltime.go deleted file mode 100644 index 316a48a..0000000 --- a/vendor/github.com/go-sql-driver/mysql/nulltime.go +++ /dev/null @@ -1,71 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql" - "database/sql/driver" - "fmt" - "time" -) - -// NullTime represents a time.Time that may be NULL. -// NullTime implements the Scanner interface so -// it can be used as a scan destination: -// -// var nt NullTime -// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt) -// ... -// if nt.Valid { -// // use nt.Time -// } else { -// // NULL value -// } -// -// # This NullTime implementation is not driver-specific -// -// Deprecated: NullTime doesn't honor the loc DSN parameter. -// NullTime.Scan interprets a time as UTC, not the loc DSN parameter. -// Use sql.NullTime instead. -type NullTime sql.NullTime - -// Scan implements the Scanner interface. -// The value type must be time.Time or string / []byte (formatted time-string), -// otherwise Scan fails. -func (nt *NullTime) Scan(value any) (err error) { - if value == nil { - nt.Time, nt.Valid = time.Time{}, false - return - } - - switch v := value.(type) { - case time.Time: - nt.Time, nt.Valid = v, true - return - case []byte: - nt.Time, err = parseDateTime(v, time.UTC) - nt.Valid = (err == nil) - return - case string: - nt.Time, err = parseDateTime([]byte(v), time.UTC) - nt.Valid = (err == nil) - return - } - - nt.Valid = false - return fmt.Errorf("can't convert %T to time.Time", value) -} - -// Value implements the driver Valuer interface. -func (nt NullTime) Value() (driver.Value, error) { - if !nt.Valid { - return nil, nil - } - return nt.Time, nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/packets.go b/vendor/github.com/go-sql-driver/mysql/packets.go deleted file mode 100644 index 90a3472..0000000 --- a/vendor/github.com/go-sql-driver/mysql/packets.go +++ /dev/null @@ -1,1406 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "crypto/tls" - "database/sql/driver" - "encoding/binary" - "encoding/json" - "fmt" - "io" - "math" - "strconv" - "time" -) - -// Packets documentation: -// http://dev.mysql.com/doc/internals/en/client-server-protocol.html - -// Read packet to buffer 'data' -func (mc *mysqlConn) readPacket() ([]byte, error) { - var prevData []byte - for { - // read packet header - data, err := mc.buf.readNext(4) - if err != nil { - if cerr := mc.canceled.Value(); cerr != nil { - return nil, cerr - } - mc.log(err) - mc.Close() - return nil, ErrInvalidConn - } - - // packet length [24 bit] - pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) - - // check packet sync [8 bit] - if data[3] != mc.sequence { - mc.Close() - if data[3] > mc.sequence { - return nil, ErrPktSyncMul - } - return nil, ErrPktSync - } - mc.sequence++ - - // packets with length 0 terminate a previous packet which is a - // multiple of (2^24)-1 bytes long - if pktLen == 0 { - // there was no previous packet - if prevData == nil { - mc.log(ErrMalformPkt) - mc.Close() - return nil, ErrInvalidConn - } - - return prevData, nil - } - - // read packet body [pktLen bytes] - data, err = mc.buf.readNext(pktLen) - if err != nil { - if cerr := mc.canceled.Value(); cerr != nil { - return nil, cerr - } - mc.log(err) - mc.Close() - return nil, ErrInvalidConn - } - - // return data if this was the last packet - if pktLen < maxPacketSize { - // zero allocations for non-split packets - if prevData == nil { - return data, nil - } - - return append(prevData, data...), nil - } - - prevData = append(prevData, data...) - } -} - -// Write packet buffer 'data' -func (mc *mysqlConn) writePacket(data []byte) error { - pktLen := len(data) - 4 - - if pktLen > mc.maxAllowedPacket { - return ErrPktTooLarge - } - - for { - var size int - if pktLen >= maxPacketSize { - data[0] = 0xff - data[1] = 0xff - data[2] = 0xff - size = maxPacketSize - } else { - data[0] = byte(pktLen) - data[1] = byte(pktLen >> 8) - data[2] = byte(pktLen >> 16) - size = pktLen - } - data[3] = mc.sequence - - // Write packet - if mc.writeTimeout > 0 { - if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil { - return err - } - } - - n, err := mc.netConn.Write(data[:4+size]) - if err == nil && n == 4+size { - mc.sequence++ - if size != maxPacketSize { - return nil - } - pktLen -= size - data = data[size:] - continue - } - - // Handle error - if err == nil { // n != len(data) - mc.cleanup() - mc.log(ErrMalformPkt) - } else { - if cerr := mc.canceled.Value(); cerr != nil { - return cerr - } - if n == 0 && pktLen == len(data)-4 { - // only for the first loop iteration when nothing was written yet - return errBadConnNoWrite - } - mc.cleanup() - mc.log(err) - } - return ErrInvalidConn - } -} - -/****************************************************************************** -* Initialization Process * -******************************************************************************/ - -// Handshake Initialization Packet -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake -func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) { - data, err = mc.readPacket() - if err != nil { - // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since - // in connection initialization we don't risk retrying non-idempotent actions. - if err == ErrInvalidConn { - return nil, "", driver.ErrBadConn - } - return - } - - if data[0] == iERR { - return nil, "", mc.handleErrorPacket(data) - } - - // protocol version [1 byte] - if data[0] < minProtocolVersion { - return nil, "", fmt.Errorf( - "unsupported protocol version %d. Version %d or higher is required", - data[0], - minProtocolVersion, - ) - } - - // server version [null terminated string] - // connection id [4 bytes] - pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4 - - // first part of the password cipher [8 bytes] - authData := data[pos : pos+8] - - // (filler) always 0x00 [1 byte] - pos += 8 + 1 - - // capability flags (lower 2 bytes) [2 bytes] - mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) - if mc.flags&clientProtocol41 == 0 { - return nil, "", ErrOldProtocol - } - if mc.flags&clientSSL == 0 && mc.cfg.TLS != nil { - if mc.cfg.AllowFallbackToPlaintext { - mc.cfg.TLS = nil - } else { - return nil, "", ErrNoTLS - } - } - pos += 2 - - if len(data) > pos { - // character set [1 byte] - // status flags [2 bytes] - // capability flags (upper 2 bytes) [2 bytes] - // length of auth-plugin-data [1 byte] - // reserved (all [00]) [10 bytes] - pos += 1 + 2 + 2 + 1 + 10 - - // second part of the password cipher [minimum 13 bytes], - // where len=MAX(13, length of auth-plugin-data - 8) - // - // The web documentation is ambiguous about the length. However, - // according to mysql-5.7/sql/auth/sql_authentication.cc line 538, - // the 13th byte is "\0 byte, terminating the second part of - // a scramble". So the second part of the password cipher is - // a NULL terminated string that's at least 13 bytes with the - // last byte being NULL. - // - // The official Python library uses the fixed length 12 - // which seems to work but technically could have a hidden bug. - authData = append(authData, data[pos:pos+12]...) - pos += 13 - - // EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2) - // \NUL otherwise - if end := bytes.IndexByte(data[pos:], 0x00); end != -1 { - plugin = string(data[pos : pos+end]) - } else { - plugin = string(data[pos:]) - } - - // make a memory safe copy of the cipher slice - var b [20]byte - copy(b[:], authData) - return b[:], plugin, nil - } - - // make a memory safe copy of the cipher slice - var b [8]byte - copy(b[:], authData) - return b[:], plugin, nil -} - -// Client Authentication Packet -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse -func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error { - // Adjust client flags based on server support - clientFlags := clientProtocol41 | - clientSecureConn | - clientLongPassword | - clientTransactions | - clientLocalFiles | - clientPluginAuth | - clientMultiResults | - clientConnectAttrs | - mc.flags&clientLongFlag - - if mc.cfg.ClientFoundRows { - clientFlags |= clientFoundRows - } - - // To enable TLS / SSL - if mc.cfg.TLS != nil { - clientFlags |= clientSSL - } - - if mc.cfg.MultiStatements { - clientFlags |= clientMultiStatements - } - - // encode length of the auth plugin data - var authRespLEIBuf [9]byte - authRespLen := len(authResp) - authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen)) - if len(authRespLEI) > 1 { - // if the length can not be written in 1 byte, it must be written as a - // length encoded integer - clientFlags |= clientPluginAuthLenEncClientData - } - - pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1 - - // To specify a db name - if n := len(mc.cfg.DBName); n > 0 { - clientFlags |= clientConnectWithDB - pktLen += n + 1 - } - - // encode length of the connection attributes - var connAttrsLEIBuf [9]byte - connAttrsLen := len(mc.connector.encodedAttributes) - connAttrsLEI := appendLengthEncodedInteger(connAttrsLEIBuf[:0], uint64(connAttrsLen)) - pktLen += len(connAttrsLEI) + len(mc.connector.encodedAttributes) - - // Calculate packet length and get buffer with that size - data, err := mc.buf.takeBuffer(pktLen + 4) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite - } - - // ClientFlags [32 bit] - data[4] = byte(clientFlags) - data[5] = byte(clientFlags >> 8) - data[6] = byte(clientFlags >> 16) - data[7] = byte(clientFlags >> 24) - - // MaxPacketSize [32 bit] (none) - data[8] = 0x00 - data[9] = 0x00 - data[10] = 0x00 - data[11] = 0x00 - - // Collation ID [1 byte] - cname := mc.cfg.Collation - if cname == "" { - cname = defaultCollation - } - var found bool - data[12], found = collations[cname] - if !found { - // Note possibility for false negatives: - // could be triggered although the collation is valid if the - // collations map does not contain entries the server supports. - return fmt.Errorf("unknown collation: %q", cname) - } - - // Filler [23 bytes] (all 0x00) - pos := 13 - for ; pos < 13+23; pos++ { - data[pos] = 0 - } - - // SSL Connection Request Packet - // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest - if mc.cfg.TLS != nil { - // Send TLS / SSL request packet - if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil { - return err - } - - // Switch to TLS - tlsConn := tls.Client(mc.netConn, mc.cfg.TLS) - if err := tlsConn.Handshake(); err != nil { - return err - } - mc.netConn = tlsConn - mc.buf.nc = tlsConn - } - - // User [null terminated string] - if len(mc.cfg.User) > 0 { - pos += copy(data[pos:], mc.cfg.User) - } - data[pos] = 0x00 - pos++ - - // Auth Data [length encoded integer] - pos += copy(data[pos:], authRespLEI) - pos += copy(data[pos:], authResp) - - // Databasename [null terminated string] - if len(mc.cfg.DBName) > 0 { - pos += copy(data[pos:], mc.cfg.DBName) - data[pos] = 0x00 - pos++ - } - - pos += copy(data[pos:], plugin) - data[pos] = 0x00 - pos++ - - // Connection Attributes - pos += copy(data[pos:], connAttrsLEI) - pos += copy(data[pos:], []byte(mc.connector.encodedAttributes)) - - // Send Auth packet - return mc.writePacket(data[:pos]) -} - -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse -func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { - pktLen := 4 + len(authData) - data, err := mc.buf.takeSmallBuffer(pktLen) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite - } - - // Add the auth data [EOF] - copy(data[4:], authData) - return mc.writePacket(data) -} - -/****************************************************************************** -* Command Packets * -******************************************************************************/ - -func (mc *mysqlConn) writeCommandPacket(command byte) error { - // Reset Packet Sequence - mc.sequence = 0 - - data, err := mc.buf.takeSmallBuffer(4 + 1) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite - } - - // Add command byte - data[4] = command - - // Send CMD packet - return mc.writePacket(data) -} - -func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { - // Reset Packet Sequence - mc.sequence = 0 - - pktLen := 1 + len(arg) - data, err := mc.buf.takeBuffer(pktLen + 4) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite - } - - // Add command byte - data[4] = command - - // Add arg - copy(data[5:], arg) - - // Send CMD packet - return mc.writePacket(data) -} - -func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { - // Reset Packet Sequence - mc.sequence = 0 - - data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite - } - - // Add command byte - data[4] = command - - // Add arg [32 bit] - data[5] = byte(arg) - data[6] = byte(arg >> 8) - data[7] = byte(arg >> 16) - data[8] = byte(arg >> 24) - - // Send CMD packet - return mc.writePacket(data) -} - -/****************************************************************************** -* Result Packets * -******************************************************************************/ - -func (mc *mysqlConn) readAuthResult() ([]byte, string, error) { - data, err := mc.readPacket() - if err != nil { - return nil, "", err - } - - // packet indicator - switch data[0] { - - case iOK: - // resultUnchanged, since auth happens before any queries or - // commands have been executed. - return nil, "", mc.resultUnchanged().handleOkPacket(data) - - case iAuthMoreData: - return data[1:], "", err - - case iEOF: - if len(data) == 1 { - // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest - return nil, "mysql_old_password", nil - } - pluginEndIndex := bytes.IndexByte(data, 0x00) - if pluginEndIndex < 0 { - return nil, "", ErrMalformPkt - } - plugin := string(data[1:pluginEndIndex]) - authData := data[pluginEndIndex+1:] - return authData, plugin, nil - - default: // Error otherwise - return nil, "", mc.handleErrorPacket(data) - } -} - -// Returns error if Packet is not a 'Result OK'-Packet -func (mc *okHandler) readResultOK() error { - data, err := mc.conn().readPacket() - if err != nil { - return err - } - - if data[0] == iOK { - return mc.handleOkPacket(data) - } - return mc.conn().handleErrorPacket(data) -} - -// Result Set Header Packet -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset -func (mc *okHandler) readResultSetHeaderPacket() (int, error) { - // handleOkPacket replaces both values; other cases leave the values unchanged. - mc.result.affectedRows = append(mc.result.affectedRows, 0) - mc.result.insertIds = append(mc.result.insertIds, 0) - - data, err := mc.conn().readPacket() - if err == nil { - switch data[0] { - - case iOK: - return 0, mc.handleOkPacket(data) - - case iERR: - return 0, mc.conn().handleErrorPacket(data) - - case iLocalInFile: - return 0, mc.handleInFileRequest(string(data[1:])) - } - - // column count - num, _, _ := readLengthEncodedInteger(data) - // ignore remaining data in the packet. see #1478. - return int(num), nil - } - return 0, err -} - -// Error Packet -// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet -func (mc *mysqlConn) handleErrorPacket(data []byte) error { - if data[0] != iERR { - return ErrMalformPkt - } - - // 0xff [1 byte] - - // Error Number [16 bit uint] - errno := binary.LittleEndian.Uint16(data[1:3]) - - // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION - // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) - if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { - // Oops; we are connected to a read-only connection, and won't be able - // to issue any write statements. Since RejectReadOnly is configured, - // we throw away this connection hoping this one would have write - // permission. This is specifically for a possible race condition - // during failover (e.g. on AWS Aurora). See README.md for more. - // - // We explicitly close the connection before returning - // driver.ErrBadConn to ensure that `database/sql` purges this - // connection and initiates a new one for next statement next time. - mc.Close() - return driver.ErrBadConn - } - - me := &MySQLError{Number: errno} - - pos := 3 - - // SQL State [optional: # + 5bytes string] - if data[3] == 0x23 { - copy(me.SQLState[:], data[4:4+5]) - pos = 9 - } - - // Error Message [string] - me.Message = string(data[pos:]) - - return me -} - -func readStatus(b []byte) statusFlag { - return statusFlag(b[0]) | statusFlag(b[1])<<8 -} - -// Returns an instance of okHandler for codepaths where mysqlConn.result doesn't -// need to be cleared first (e.g. during authentication, or while additional -// resultsets are being fetched.) -func (mc *mysqlConn) resultUnchanged() *okHandler { - return (*okHandler)(mc) -} - -// okHandler represents the state of the connection when mysqlConn.result has -// been prepared for processing of OK packets. -// -// To correctly populate mysqlConn.result (updated by handleOkPacket()), all -// callpaths must either: -// -// 1. first clear it using clearResult(), or -// 2. confirm that they don't need to (by calling resultUnchanged()). -// -// Both return an instance of type *okHandler. -type okHandler mysqlConn - -// Exposes the underlying type's methods. -func (mc *okHandler) conn() *mysqlConn { - return (*mysqlConn)(mc) -} - -// clearResult clears the connection's stored affectedRows and insertIds -// fields. -// -// It returns a handler that can process OK responses. -func (mc *mysqlConn) clearResult() *okHandler { - mc.result = mysqlResult{} - return (*okHandler)(mc) -} - -// Ok Packet -// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet -func (mc *okHandler) handleOkPacket(data []byte) error { - var n, m int - var affectedRows, insertId uint64 - - // 0x00 [1 byte] - - // Affected rows [Length Coded Binary] - affectedRows, _, n = readLengthEncodedInteger(data[1:]) - - // Insert id [Length Coded Binary] - insertId, _, m = readLengthEncodedInteger(data[1+n:]) - - // Update for the current statement result (only used by - // readResultSetHeaderPacket). - if len(mc.result.affectedRows) > 0 { - mc.result.affectedRows[len(mc.result.affectedRows)-1] = int64(affectedRows) - } - if len(mc.result.insertIds) > 0 { - mc.result.insertIds[len(mc.result.insertIds)-1] = int64(insertId) - } - - // server_status [2 bytes] - mc.status = readStatus(data[1+n+m : 1+n+m+2]) - if mc.status&statusMoreResultsExists != 0 { - return nil - } - - // warning count [2 bytes] - - return nil -} - -// Read Packets as Field Packets until EOF-Packet or an Error appears -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41 -func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { - columns := make([]mysqlField, count) - - for i := 0; ; i++ { - data, err := mc.readPacket() - if err != nil { - return nil, err - } - - // EOF Packet - if data[0] == iEOF && (len(data) == 5 || len(data) == 1) { - if i == count { - return columns, nil - } - return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns)) - } - - // Catalog - pos, err := skipLengthEncodedString(data) - if err != nil { - return nil, err - } - - // Database [len coded string] - n, err := skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - - // Table [len coded string] - if mc.cfg.ColumnsWithAlias { - tableName, _, n, err := readLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - columns[i].tableName = string(tableName) - } else { - n, err = skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - } - - // Original table [len coded string] - n, err = skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - - // Name [len coded string] - name, _, n, err := readLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - columns[i].name = string(name) - pos += n - - // Original name [len coded string] - n, err = skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - - // Filler [uint8] - pos++ - - // Charset [charset, collation uint8] - columns[i].charSet = data[pos] - pos += 2 - - // Length [uint32] - columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4]) - pos += 4 - - // Field type [uint8] - columns[i].fieldType = fieldType(data[pos]) - pos++ - - // Flags [uint16] - columns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) - pos += 2 - - // Decimals [uint8] - columns[i].decimals = data[pos] - //pos++ - - // Default value [len coded binary] - //if pos < len(data) { - // defaultVal, _, err = bytesToLengthCodedBinary(data[pos:]) - //} - } -} - -// Read Packets as Field Packets until EOF-Packet or an Error appears -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow -func (rows *textRows) readRow(dest []driver.Value) error { - mc := rows.mc - - if rows.rs.done { - return io.EOF - } - - data, err := mc.readPacket() - if err != nil { - return err - } - - // EOF Packet - if data[0] == iEOF && len(data) == 5 { - // server_status [2 bytes] - rows.mc.status = readStatus(data[3:]) - rows.rs.done = true - if !rows.HasNextResultSet() { - rows.mc = nil - } - return io.EOF - } - if data[0] == iERR { - rows.mc = nil - return mc.handleErrorPacket(data) - } - - // RowSet Packet - var ( - n int - isNull bool - pos int = 0 - ) - - for i := range dest { - // Read bytes and convert to string - var buf []byte - buf, isNull, n, err = readLengthEncodedString(data[pos:]) - pos += n - - if err != nil { - return err - } - - if isNull { - dest[i] = nil - continue - } - - switch rows.rs.columns[i].fieldType { - case fieldTypeTimestamp, - fieldTypeDateTime, - fieldTypeDate, - fieldTypeNewDate: - if mc.parseTime { - dest[i], err = parseDateTime(buf, mc.cfg.Loc) - } else { - dest[i] = buf - } - - case fieldTypeTiny, fieldTypeShort, fieldTypeInt24, fieldTypeYear, fieldTypeLong: - dest[i], err = strconv.ParseInt(string(buf), 10, 64) - - case fieldTypeLongLong: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i], err = strconv.ParseUint(string(buf), 10, 64) - } else { - dest[i], err = strconv.ParseInt(string(buf), 10, 64) - } - - case fieldTypeFloat: - var d float64 - d, err = strconv.ParseFloat(string(buf), 32) - dest[i] = float32(d) - - case fieldTypeDouble: - dest[i], err = strconv.ParseFloat(string(buf), 64) - - default: - dest[i] = buf - } - if err != nil { - return err - } - } - - return nil -} - -// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read -func (mc *mysqlConn) readUntilEOF() error { - for { - data, err := mc.readPacket() - if err != nil { - return err - } - - switch data[0] { - case iERR: - return mc.handleErrorPacket(data) - case iEOF: - if len(data) == 5 { - mc.status = readStatus(data[3:]) - } - return nil - } - } -} - -/****************************************************************************** -* Prepared Statements * -******************************************************************************/ - -// Prepare Result Packets -// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html -func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { - data, err := stmt.mc.readPacket() - if err == nil { - // packet indicator [1 byte] - if data[0] != iOK { - return 0, stmt.mc.handleErrorPacket(data) - } - - // statement id [4 bytes] - stmt.id = binary.LittleEndian.Uint32(data[1:5]) - - // Column count [16 bit uint] - columnCount := binary.LittleEndian.Uint16(data[5:7]) - - // Param count [16 bit uint] - stmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9])) - - // Reserved [8 bit] - - // Warning count [16 bit uint] - - return columnCount, nil - } - return 0, err -} - -// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html -func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error { - maxLen := stmt.mc.maxAllowedPacket - 1 - pktLen := maxLen - - // After the header (bytes 0-3) follows before the data: - // 1 byte command - // 4 bytes stmtID - // 2 bytes paramID - const dataOffset = 1 + 4 + 2 - - // Cannot use the write buffer since - // a) the buffer is too small - // b) it is in use - data := make([]byte, 4+1+4+2+len(arg)) - - copy(data[4+dataOffset:], arg) - - for argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset { - if dataOffset+argLen < maxLen { - pktLen = dataOffset + argLen - } - - stmt.mc.sequence = 0 - // Add command byte [1 byte] - data[4] = comStmtSendLongData - - // Add stmtID [32 bit] - data[5] = byte(stmt.id) - data[6] = byte(stmt.id >> 8) - data[7] = byte(stmt.id >> 16) - data[8] = byte(stmt.id >> 24) - - // Add paramID [16 bit] - data[9] = byte(paramID) - data[10] = byte(paramID >> 8) - - // Send CMD packet - err := stmt.mc.writePacket(data[:4+pktLen]) - if err == nil { - data = data[pktLen-dataOffset:] - continue - } - return err - - } - - // Reset Packet Sequence - stmt.mc.sequence = 0 - return nil -} - -// Execute Prepared Statement -// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html -func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { - if len(args) != stmt.paramCount { - return fmt.Errorf( - "argument count mismatch (got: %d; has: %d)", - len(args), - stmt.paramCount, - ) - } - - const minPktLen = 4 + 1 + 4 + 1 + 4 - mc := stmt.mc - - // Determine threshold dynamically to avoid packet size shortage. - longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) - if longDataSize < 64 { - longDataSize = 64 - } - - // Reset packet-sequence - mc.sequence = 0 - - var data []byte - var err error - - if len(args) == 0 { - data, err = mc.buf.takeBuffer(minPktLen) - } else { - data, err = mc.buf.takeCompleteBuffer() - // In this case the len(data) == cap(data) which is used to optimise the flow below. - } - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite - } - - // command [1 byte] - data[4] = comStmtExecute - - // statement_id [4 bytes] - data[5] = byte(stmt.id) - data[6] = byte(stmt.id >> 8) - data[7] = byte(stmt.id >> 16) - data[8] = byte(stmt.id >> 24) - - // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte] - data[9] = 0x00 - - // iteration_count (uint32(1)) [4 bytes] - data[10] = 0x01 - data[11] = 0x00 - data[12] = 0x00 - data[13] = 0x00 - - if len(args) > 0 { - pos := minPktLen - - var nullMask []byte - if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) { - // buffer has to be extended but we don't know by how much so - // we depend on append after all data with known sizes fit. - // We stop at that because we deal with a lot of columns here - // which makes the required allocation size hard to guess. - tmp := make([]byte, pos+maskLen+typesLen) - copy(tmp[:pos], data[:pos]) - data = tmp - nullMask = data[pos : pos+maskLen] - // No need to clean nullMask as make ensures that. - pos += maskLen - } else { - nullMask = data[pos : pos+maskLen] - for i := range nullMask { - nullMask[i] = 0 - } - pos += maskLen - } - - // newParameterBoundFlag 1 [1 byte] - data[pos] = 0x01 - pos++ - - // type of each parameter [len(args)*2 bytes] - paramTypes := data[pos:] - pos += len(args) * 2 - - // value of each parameter [n bytes] - paramValues := data[pos:pos] - valuesCap := cap(paramValues) - - for i, arg := range args { - // build NULL-bitmap - if arg == nil { - nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = byte(fieldTypeNULL) - paramTypes[i+i+1] = 0x00 - continue - } - - if v, ok := arg.(json.RawMessage); ok { - arg = []byte(v) - } - // cache types and values - switch v := arg.(type) { - case int64: - paramTypes[i+i] = byte(fieldTypeLongLong) - paramTypes[i+i+1] = 0x00 - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - uint64(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(uint64(v))..., - ) - } - - case uint64: - paramTypes[i+i] = byte(fieldTypeLongLong) - paramTypes[i+i+1] = 0x80 // type is unsigned - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - uint64(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(uint64(v))..., - ) - } - - case float64: - paramTypes[i+i] = byte(fieldTypeDouble) - paramTypes[i+i+1] = 0x00 - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - math.Float64bits(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(math.Float64bits(v))..., - ) - } - - case bool: - paramTypes[i+i] = byte(fieldTypeTiny) - paramTypes[i+i+1] = 0x00 - - if v { - paramValues = append(paramValues, 0x01) - } else { - paramValues = append(paramValues, 0x00) - } - - case []byte: - // Common case (non-nil value) first - if v != nil { - paramTypes[i+i] = byte(fieldTypeString) - paramTypes[i+i+1] = 0x00 - - if len(v) < longDataSize { - paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(v)), - ) - paramValues = append(paramValues, v...) - } else { - if err := stmt.writeCommandLongData(i, v); err != nil { - return err - } - } - continue - } - - // Handle []byte(nil) as a NULL value - nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = byte(fieldTypeNULL) - paramTypes[i+i+1] = 0x00 - - case string: - paramTypes[i+i] = byte(fieldTypeString) - paramTypes[i+i+1] = 0x00 - - if len(v) < longDataSize { - paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(v)), - ) - paramValues = append(paramValues, v...) - } else { - if err := stmt.writeCommandLongData(i, []byte(v)); err != nil { - return err - } - } - - case time.Time: - paramTypes[i+i] = byte(fieldTypeString) - paramTypes[i+i+1] = 0x00 - - var a [64]byte - var b = a[:0] - - if v.IsZero() { - b = append(b, "0000-00-00"...) - } else { - b, err = appendDateTime(b, v.In(mc.cfg.Loc), mc.cfg.timeTruncate) - if err != nil { - return err - } - } - - paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(b)), - ) - paramValues = append(paramValues, b...) - - default: - return fmt.Errorf("cannot convert type: %T", arg) - } - } - - // Check if param values exceeded the available buffer - // In that case we must build the data packet with the new values buffer - if valuesCap != cap(paramValues) { - data = append(data[:pos], paramValues...) - if err = mc.buf.store(data); err != nil { - mc.log(err) - return errBadConnNoWrite - } - } - - pos += len(paramValues) - data = data[:pos] - } - - return mc.writePacket(data) -} - -// For each remaining resultset in the stream, discards its rows and updates -// mc.affectedRows and mc.insertIds. -func (mc *okHandler) discardResults() error { - for mc.status&statusMoreResultsExists != 0 { - resLen, err := mc.readResultSetHeaderPacket() - if err != nil { - return err - } - if resLen > 0 { - // columns - if err := mc.conn().readUntilEOF(); err != nil { - return err - } - // rows - if err := mc.conn().readUntilEOF(); err != nil { - return err - } - } - } - return nil -} - -// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html -func (rows *binaryRows) readRow(dest []driver.Value) error { - data, err := rows.mc.readPacket() - if err != nil { - return err - } - - // packet indicator [1 byte] - if data[0] != iOK { - // EOF Packet - if data[0] == iEOF && len(data) == 5 { - rows.mc.status = readStatus(data[3:]) - rows.rs.done = true - if !rows.HasNextResultSet() { - rows.mc = nil - } - return io.EOF - } - mc := rows.mc - rows.mc = nil - - // Error otherwise - return mc.handleErrorPacket(data) - } - - // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] - pos := 1 + (len(dest)+7+2)>>3 - nullMask := data[1:pos] - - for i := range dest { - // Field is NULL - // (byte >> bit-pos) % 2 == 1 - if ((nullMask[(i+2)>>3] >> uint((i+2)&7)) & 1) == 1 { - dest[i] = nil - continue - } - - // Convert to byte-coded string - switch rows.rs.columns[i].fieldType { - case fieldTypeNULL: - dest[i] = nil - continue - - // Numeric Types - case fieldTypeTiny: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i] = int64(data[pos]) - } else { - dest[i] = int64(int8(data[pos])) - } - pos++ - continue - - case fieldTypeShort, fieldTypeYear: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2])) - } else { - dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2]))) - } - pos += 2 - continue - - case fieldTypeInt24, fieldTypeLong: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4])) - } else { - dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4]))) - } - pos += 4 - continue - - case fieldTypeLongLong: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - val := binary.LittleEndian.Uint64(data[pos : pos+8]) - if val > math.MaxInt64 { - dest[i] = uint64ToString(val) - } else { - dest[i] = int64(val) - } - } else { - dest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8])) - } - pos += 8 - continue - - case fieldTypeFloat: - dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])) - pos += 4 - continue - - case fieldTypeDouble: - dest[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[pos : pos+8])) - pos += 8 - continue - - // Length coded Binary Strings - case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, - fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, - fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, - fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON: - var isNull bool - var n int - dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) - pos += n - if err == nil { - if !isNull { - continue - } else { - dest[i] = nil - continue - } - } - return err - - case - fieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD - fieldTypeTime, // Time [-][H]HH:MM:SS[.fractal] - fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal] - - num, isNull, n := readLengthEncodedInteger(data[pos:]) - pos += n - - switch { - case isNull: - dest[i] = nil - continue - case rows.rs.columns[i].fieldType == fieldTypeTime: - // database/sql does not support an equivalent to TIME, return a string - var dstlen uint8 - switch decimals := rows.rs.columns[i].decimals; decimals { - case 0x00, 0x1f: - dstlen = 8 - case 1, 2, 3, 4, 5, 6: - dstlen = 8 + 1 + decimals - default: - return fmt.Errorf( - "protocol error, illegal decimals value %d", - rows.rs.columns[i].decimals, - ) - } - dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen) - case rows.mc.parseTime: - dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) - default: - var dstlen uint8 - if rows.rs.columns[i].fieldType == fieldTypeDate { - dstlen = 10 - } else { - switch decimals := rows.rs.columns[i].decimals; decimals { - case 0x00, 0x1f: - dstlen = 19 - case 1, 2, 3, 4, 5, 6: - dstlen = 19 + 1 + decimals - default: - return fmt.Errorf( - "protocol error, illegal decimals value %d", - rows.rs.columns[i].decimals, - ) - } - } - dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen) - } - - if err == nil { - pos += int(num) - continue - } else { - return err - } - - // Please report if this happens! - default: - return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType) - } - } - - return nil -} diff --git a/vendor/github.com/go-sql-driver/mysql/result.go b/vendor/github.com/go-sql-driver/mysql/result.go deleted file mode 100644 index d516314..0000000 --- a/vendor/github.com/go-sql-driver/mysql/result.go +++ /dev/null @@ -1,50 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import "database/sql/driver" - -// Result exposes data not available through *connection.Result. -// -// This is accessible by executing statements using sql.Conn.Raw() and -// downcasting the returned result: -// -// res, err := rawConn.Exec(...) -// res.(mysql.Result).AllRowsAffected() -type Result interface { - driver.Result - // AllRowsAffected returns a slice containing the affected rows for each - // executed statement. - AllRowsAffected() []int64 - // AllLastInsertIds returns a slice containing the last inserted ID for each - // executed statement. - AllLastInsertIds() []int64 -} - -type mysqlResult struct { - // One entry in both slices is created for every executed statement result. - affectedRows []int64 - insertIds []int64 -} - -func (res *mysqlResult) LastInsertId() (int64, error) { - return res.insertIds[len(res.insertIds)-1], nil -} - -func (res *mysqlResult) RowsAffected() (int64, error) { - return res.affectedRows[len(res.affectedRows)-1], nil -} - -func (res *mysqlResult) AllLastInsertIds() []int64 { - return append([]int64{}, res.insertIds...) // defensive copy -} - -func (res *mysqlResult) AllRowsAffected() []int64 { - return append([]int64{}, res.affectedRows...) // defensive copy -} diff --git a/vendor/github.com/go-sql-driver/mysql/rows.go b/vendor/github.com/go-sql-driver/mysql/rows.go deleted file mode 100644 index 81fa606..0000000 --- a/vendor/github.com/go-sql-driver/mysql/rows.go +++ /dev/null @@ -1,232 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql/driver" - "io" - "math" - "reflect" -) - -type resultSet struct { - columns []mysqlField - columnNames []string - done bool -} - -type mysqlRows struct { - mc *mysqlConn - rs resultSet - finish func() -} - -type binaryRows struct { - mysqlRows -} - -type textRows struct { - mysqlRows -} - -func (rows *mysqlRows) Columns() []string { - if rows.rs.columnNames != nil { - return rows.rs.columnNames - } - - columns := make([]string, len(rows.rs.columns)) - if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { - for i := range columns { - if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { - columns[i] = tableName + "." + rows.rs.columns[i].name - } else { - columns[i] = rows.rs.columns[i].name - } - } - } else { - for i := range columns { - columns[i] = rows.rs.columns[i].name - } - } - - rows.rs.columnNames = columns - return columns -} - -func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { - return rows.rs.columns[i].typeDatabaseName() -} - -// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { -// return int64(rows.rs.columns[i].length), true -// } - -func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { - return rows.rs.columns[i].flags&flagNotNULL == 0, true -} - -func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { - column := rows.rs.columns[i] - decimals := int64(column.decimals) - - switch column.fieldType { - case fieldTypeDecimal, fieldTypeNewDecimal: - if decimals > 0 { - return int64(column.length) - 2, decimals, true - } - return int64(column.length) - 1, decimals, true - case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: - return decimals, decimals, true - case fieldTypeFloat, fieldTypeDouble: - if decimals == 0x1f { - return math.MaxInt64, math.MaxInt64, true - } - return math.MaxInt64, decimals, true - } - - return 0, 0, false -} - -func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { - return rows.rs.columns[i].scanType() -} - -func (rows *mysqlRows) Close() (err error) { - if f := rows.finish; f != nil { - f() - rows.finish = nil - } - - mc := rows.mc - if mc == nil { - return nil - } - if err := mc.error(); err != nil { - return err - } - - // flip the buffer for this connection if we need to drain it. - // note that for a successful query (i.e. one where rows.next() - // has been called until it returns false), `rows.mc` will be nil - // by the time the user calls `(*Rows).Close`, so we won't reach this - // see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47 - mc.buf.flip() - - // Remove unread packets from stream - if !rows.rs.done { - err = mc.readUntilEOF() - } - if err == nil { - handleOk := mc.clearResult() - if err = handleOk.discardResults(); err != nil { - return err - } - } - - rows.mc = nil - return err -} - -func (rows *mysqlRows) HasNextResultSet() (b bool) { - if rows.mc == nil { - return false - } - return rows.mc.status&statusMoreResultsExists != 0 -} - -func (rows *mysqlRows) nextResultSet() (int, error) { - if rows.mc == nil { - return 0, io.EOF - } - if err := rows.mc.error(); err != nil { - return 0, err - } - - // Remove unread packets from stream - if !rows.rs.done { - if err := rows.mc.readUntilEOF(); err != nil { - return 0, err - } - rows.rs.done = true - } - - if !rows.HasNextResultSet() { - rows.mc = nil - return 0, io.EOF - } - rows.rs = resultSet{} - // rows.mc.affectedRows and rows.mc.insertIds accumulate on each call to - // nextResultSet. - resLen, err := rows.mc.resultUnchanged().readResultSetHeaderPacket() - if err != nil { - // Clean up about multi-results flag - rows.rs.done = true - rows.mc.status = rows.mc.status & (^statusMoreResultsExists) - } - return resLen, err -} - -func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { - for { - resLen, err := rows.nextResultSet() - if err != nil { - return 0, err - } - - if resLen > 0 { - return resLen, nil - } - - rows.rs.done = true - } -} - -func (rows *binaryRows) NextResultSet() error { - resLen, err := rows.nextNotEmptyResultSet() - if err != nil { - return err - } - - rows.rs.columns, err = rows.mc.readColumns(resLen) - return err -} - -func (rows *binaryRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - if err := mc.error(); err != nil { - return err - } - - // Fetch next row from stream - return rows.readRow(dest) - } - return io.EOF -} - -func (rows *textRows) NextResultSet() (err error) { - resLen, err := rows.nextNotEmptyResultSet() - if err != nil { - return err - } - - rows.rs.columns, err = rows.mc.readColumns(resLen) - return err -} - -func (rows *textRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - if err := mc.error(); err != nil { - return err - } - - // Fetch next row from stream - return rows.readRow(dest) - } - return io.EOF -} diff --git a/vendor/github.com/go-sql-driver/mysql/statement.go b/vendor/github.com/go-sql-driver/mysql/statement.go deleted file mode 100644 index 0436f22..0000000 --- a/vendor/github.com/go-sql-driver/mysql/statement.go +++ /dev/null @@ -1,217 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql/driver" - "encoding/json" - "fmt" - "io" - "reflect" -) - -type mysqlStmt struct { - mc *mysqlConn - id uint32 - paramCount int -} - -func (stmt *mysqlStmt) Close() error { - if stmt.mc == nil || stmt.mc.closed.Load() { - // driver.Stmt.Close can be called more than once, thus this function - // has to be idempotent. - // See also Issue #450 and golang/go#16019. - //errLog.Print(ErrInvalidConn) - return driver.ErrBadConn - } - - err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id) - stmt.mc = nil - return err -} - -func (stmt *mysqlStmt) NumInput() int { - return stmt.paramCount -} - -func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter { - return converter{} -} - -func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) { - nv.Value, err = converter{}.ConvertValue(nv.Value) - return -} - -func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { - if stmt.mc.closed.Load() { - stmt.mc.log(ErrInvalidConn) - return nil, driver.ErrBadConn - } - // Send command - err := stmt.writeExecutePacket(args) - if err != nil { - return nil, stmt.mc.markBadConn(err) - } - - mc := stmt.mc - handleOk := stmt.mc.clearResult() - - // Read Result - resLen, err := handleOk.readResultSetHeaderPacket() - if err != nil { - return nil, err - } - - if resLen > 0 { - // Columns - if err = mc.readUntilEOF(); err != nil { - return nil, err - } - - // Rows - if err := mc.readUntilEOF(); err != nil { - return nil, err - } - } - - if err := handleOk.discardResults(); err != nil { - return nil, err - } - - copied := mc.result - return &copied, nil -} - -func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { - return stmt.query(args) -} - -func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { - if stmt.mc.closed.Load() { - stmt.mc.log(ErrInvalidConn) - return nil, driver.ErrBadConn - } - // Send command - err := stmt.writeExecutePacket(args) - if err != nil { - return nil, stmt.mc.markBadConn(err) - } - - mc := stmt.mc - - // Read Result - handleOk := stmt.mc.clearResult() - resLen, err := handleOk.readResultSetHeaderPacket() - if err != nil { - return nil, err - } - - rows := new(binaryRows) - - if resLen > 0 { - rows.mc = mc - rows.rs.columns, err = mc.readColumns(resLen) - } else { - rows.rs.done = true - - switch err := rows.NextResultSet(); err { - case nil, io.EOF: - return rows, nil - default: - return nil, err - } - } - - return rows, err -} - -var jsonType = reflect.TypeOf(json.RawMessage{}) - -type converter struct{} - -// ConvertValue mirrors the reference/default converter in database/sql/driver -// with _one_ exception. We support uint64 with their high bit and the default -// implementation does not. This function should be kept in sync with -// database/sql/driver defaultConverter.ConvertValue() except for that -// deliberate difference. -func (c converter) ConvertValue(v any) (driver.Value, error) { - if driver.IsValue(v) { - return v, nil - } - - if vr, ok := v.(driver.Valuer); ok { - sv, err := callValuerValue(vr) - if err != nil { - return nil, err - } - if driver.IsValue(sv) { - return sv, nil - } - // A value returned from the Valuer interface can be "a type handled by - // a database driver's NamedValueChecker interface" so we should accept - // uint64 here as well. - if u, ok := sv.(uint64); ok { - return u, nil - } - return nil, fmt.Errorf("non-Value type %T returned from Value", sv) - } - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Ptr: - // indirect pointers - if rv.IsNil() { - return nil, nil - } else { - return c.ConvertValue(rv.Elem().Interface()) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint(), nil - case reflect.Float32, reflect.Float64: - return rv.Float(), nil - case reflect.Bool: - return rv.Bool(), nil - case reflect.Slice: - switch t := rv.Type(); { - case t == jsonType: - return v, nil - case t.Elem().Kind() == reflect.Uint8: - return rv.Bytes(), nil - default: - return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind()) - } - case reflect.String: - return rv.String(), nil - } - return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) -} - -var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() - -// callValuerValue returns vr.Value(), with one exception: -// If vr.Value is an auto-generated method on a pointer type and the -// pointer is nil, it would panic at runtime in the panicwrap -// method. Treat it like nil instead. -// -// This is so people can implement driver.Value on value types and -// still use nil pointers to those types to mean nil/NULL, just like -// string/*string. -// -// This is an exact copy of the same-named unexported function from the -// database/sql package. -func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { - if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && - rv.IsNil() && - rv.Type().Elem().Implements(valuerReflectType) { - return nil, nil - } - return vr.Value() -} diff --git a/vendor/github.com/go-sql-driver/mysql/transaction.go b/vendor/github.com/go-sql-driver/mysql/transaction.go deleted file mode 100644 index 4a4b610..0000000 --- a/vendor/github.com/go-sql-driver/mysql/transaction.go +++ /dev/null @@ -1,31 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -type mysqlTx struct { - mc *mysqlConn -} - -func (tx *mysqlTx) Commit() (err error) { - if tx.mc == nil || tx.mc.closed.Load() { - return ErrInvalidConn - } - err = tx.mc.exec("COMMIT") - tx.mc = nil - return -} - -func (tx *mysqlTx) Rollback() (err error) { - if tx.mc == nil || tx.mc.closed.Load() { - return ErrInvalidConn - } - err = tx.mc.exec("ROLLBACK") - tx.mc = nil - return -} diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go deleted file mode 100644 index cda24fe..0000000 --- a/vendor/github.com/go-sql-driver/mysql/utils.go +++ /dev/null @@ -1,843 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "crypto/tls" - "database/sql" - "database/sql/driver" - "encoding/binary" - "errors" - "fmt" - "io" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" -) - -// Registry for custom tls.Configs -var ( - tlsConfigLock sync.RWMutex - tlsConfigRegistry map[string]*tls.Config -) - -// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open. -// Use the key as a value in the DSN where tls=value. -// -// Note: The provided tls.Config is exclusively owned by the driver after -// registering it. -// -// rootCertPool := x509.NewCertPool() -// pem, err := os.ReadFile("/path/ca-cert.pem") -// if err != nil { -// log.Fatal(err) -// } -// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { -// log.Fatal("Failed to append PEM.") -// } -// clientCert := make([]tls.Certificate, 0, 1) -// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem") -// if err != nil { -// log.Fatal(err) -// } -// clientCert = append(clientCert, certs) -// mysql.RegisterTLSConfig("custom", &tls.Config{ -// RootCAs: rootCertPool, -// Certificates: clientCert, -// }) -// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom") -func RegisterTLSConfig(key string, config *tls.Config) error { - if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" { - return fmt.Errorf("key '%s' is reserved", key) - } - - tlsConfigLock.Lock() - if tlsConfigRegistry == nil { - tlsConfigRegistry = make(map[string]*tls.Config) - } - - tlsConfigRegistry[key] = config - tlsConfigLock.Unlock() - return nil -} - -// DeregisterTLSConfig removes the tls.Config associated with key. -func DeregisterTLSConfig(key string) { - tlsConfigLock.Lock() - if tlsConfigRegistry != nil { - delete(tlsConfigRegistry, key) - } - tlsConfigLock.Unlock() -} - -func getTLSConfigClone(key string) (config *tls.Config) { - tlsConfigLock.RLock() - if v, ok := tlsConfigRegistry[key]; ok { - config = v.Clone() - } - tlsConfigLock.RUnlock() - return -} - -// Returns the bool value of the input. -// The 2nd return value indicates if the input was a valid bool value -func readBool(input string) (value bool, valid bool) { - switch input { - case "1", "true", "TRUE", "True": - return true, true - case "0", "false", "FALSE", "False": - return false, true - } - - // Not a valid bool value - return -} - -/****************************************************************************** -* Time related utils * -******************************************************************************/ - -func parseDateTime(b []byte, loc *time.Location) (time.Time, error) { - const base = "0000-00-00 00:00:00.000000" - switch len(b) { - case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" - if string(b) == base[:len(b)] { - return time.Time{}, nil - } - - year, err := parseByteYear(b) - if err != nil { - return time.Time{}, err - } - if b[4] != '-' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[4]) - } - - m, err := parseByte2Digits(b[5], b[6]) - if err != nil { - return time.Time{}, err - } - month := time.Month(m) - - if b[7] != '-' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[7]) - } - - day, err := parseByte2Digits(b[8], b[9]) - if err != nil { - return time.Time{}, err - } - if len(b) == 10 { - return time.Date(year, month, day, 0, 0, 0, 0, loc), nil - } - - if b[10] != ' ' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[10]) - } - - hour, err := parseByte2Digits(b[11], b[12]) - if err != nil { - return time.Time{}, err - } - if b[13] != ':' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[13]) - } - - min, err := parseByte2Digits(b[14], b[15]) - if err != nil { - return time.Time{}, err - } - if b[16] != ':' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[16]) - } - - sec, err := parseByte2Digits(b[17], b[18]) - if err != nil { - return time.Time{}, err - } - if len(b) == 19 { - return time.Date(year, month, day, hour, min, sec, 0, loc), nil - } - - if b[19] != '.' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[19]) - } - nsec, err := parseByteNanoSec(b[20:]) - if err != nil { - return time.Time{}, err - } - return time.Date(year, month, day, hour, min, sec, nsec, loc), nil - default: - return time.Time{}, fmt.Errorf("invalid time bytes: %s", b) - } -} - -func parseByteYear(b []byte) (int, error) { - year, n := 0, 1000 - for i := 0; i < 4; i++ { - v, err := bToi(b[i]) - if err != nil { - return 0, err - } - year += v * n - n /= 10 - } - return year, nil -} - -func parseByte2Digits(b1, b2 byte) (int, error) { - d1, err := bToi(b1) - if err != nil { - return 0, err - } - d2, err := bToi(b2) - if err != nil { - return 0, err - } - return d1*10 + d2, nil -} - -func parseByteNanoSec(b []byte) (int, error) { - ns, digit := 0, 100000 // max is 6-digits - for i := 0; i < len(b); i++ { - v, err := bToi(b[i]) - if err != nil { - return 0, err - } - ns += v * digit - digit /= 10 - } - // nanoseconds has 10-digits. (needs to scale digits) - // 10 - 6 = 4, so we have to multiple 1000. - return ns * 1000, nil -} - -func bToi(b byte) (int, error) { - if b < '0' || b > '9' { - return 0, errors.New("not [0-9]") - } - return int(b - '0'), nil -} - -func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) { - switch num { - case 0: - return time.Time{}, nil - case 4: - return time.Date( - int(binary.LittleEndian.Uint16(data[:2])), // year - time.Month(data[2]), // month - int(data[3]), // day - 0, 0, 0, 0, - loc, - ), nil - case 7: - return time.Date( - int(binary.LittleEndian.Uint16(data[:2])), // year - time.Month(data[2]), // month - int(data[3]), // day - int(data[4]), // hour - int(data[5]), // minutes - int(data[6]), // seconds - 0, - loc, - ), nil - case 11: - return time.Date( - int(binary.LittleEndian.Uint16(data[:2])), // year - time.Month(data[2]), // month - int(data[3]), // day - int(data[4]), // hour - int(data[5]), // minutes - int(data[6]), // seconds - int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds - loc, - ), nil - } - return nil, fmt.Errorf("invalid DATETIME packet length %d", num) -} - -func appendDateTime(buf []byte, t time.Time, timeTruncate time.Duration) ([]byte, error) { - if timeTruncate > 0 { - t = t.Truncate(timeTruncate) - } - - year, month, day := t.Date() - hour, min, sec := t.Clock() - nsec := t.Nanosecond() - - if year < 1 || year > 9999 { - return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap - } - year100 := year / 100 - year1 := year % 100 - - var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape - localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1] - localBuf[4] = '-' - localBuf[5], localBuf[6] = digits10[month], digits01[month] - localBuf[7] = '-' - localBuf[8], localBuf[9] = digits10[day], digits01[day] - - if hour == 0 && min == 0 && sec == 0 && nsec == 0 { - return append(buf, localBuf[:10]...), nil - } - - localBuf[10] = ' ' - localBuf[11], localBuf[12] = digits10[hour], digits01[hour] - localBuf[13] = ':' - localBuf[14], localBuf[15] = digits10[min], digits01[min] - localBuf[16] = ':' - localBuf[17], localBuf[18] = digits10[sec], digits01[sec] - - if nsec == 0 { - return append(buf, localBuf[:19]...), nil - } - nsec100000000 := nsec / 100000000 - nsec1000000 := (nsec / 1000000) % 100 - nsec10000 := (nsec / 10000) % 100 - nsec100 := (nsec / 100) % 100 - nsec1 := nsec % 100 - localBuf[19] = '.' - - // milli second - localBuf[20], localBuf[21], localBuf[22] = - digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000] - // micro second - localBuf[23], localBuf[24], localBuf[25] = - digits10[nsec10000], digits01[nsec10000], digits10[nsec100] - // nano second - localBuf[26], localBuf[27], localBuf[28] = - digits01[nsec100], digits10[nsec1], digits01[nsec1] - - // trim trailing zeros - n := len(localBuf) - for n > 0 && localBuf[n-1] == '0' { - n-- - } - - return append(buf, localBuf[:n]...), nil -} - -// zeroDateTime is used in formatBinaryDateTime to avoid an allocation -// if the DATE or DATETIME has the zero value. -// It must never be changed. -// The current behavior depends on database/sql copying the result. -var zeroDateTime = []byte("0000-00-00 00:00:00.000000") - -const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" -const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" - -func appendMicrosecs(dst, src []byte, decimals int) []byte { - if decimals <= 0 { - return dst - } - if len(src) == 0 { - return append(dst, ".000000"[:decimals+1]...) - } - - microsecs := binary.LittleEndian.Uint32(src[:4]) - p1 := byte(microsecs / 10000) - microsecs -= 10000 * uint32(p1) - p2 := byte(microsecs / 100) - microsecs -= 100 * uint32(p2) - p3 := byte(microsecs) - - switch decimals { - default: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], digits01[p2], - digits10[p3], digits01[p3], - ) - case 1: - return append(dst, '.', - digits10[p1], - ) - case 2: - return append(dst, '.', - digits10[p1], digits01[p1], - ) - case 3: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], - ) - case 4: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], digits01[p2], - ) - case 5: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], digits01[p2], - digits10[p3], - ) - } -} - -func formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) { - // length expects the deterministic length of the zero value, - // negative time and 100+ hours are automatically added if needed - if len(src) == 0 { - return zeroDateTime[:length], nil - } - var dst []byte // return value - var p1, p2, p3 byte // current digit pair - - switch length { - case 10, 19, 21, 22, 23, 24, 25, 26: - default: - t := "DATE" - if length > 10 { - t += "TIME" - } - return nil, fmt.Errorf("illegal %s length %d", t, length) - } - switch len(src) { - case 4, 7, 11: - default: - t := "DATE" - if length > 10 { - t += "TIME" - } - return nil, fmt.Errorf("illegal %s packet length %d", t, len(src)) - } - dst = make([]byte, 0, length) - // start with the date - year := binary.LittleEndian.Uint16(src[:2]) - pt := year / 100 - p1 = byte(year - 100*uint16(pt)) - p2, p3 = src[2], src[3] - dst = append(dst, - digits10[pt], digits01[pt], - digits10[p1], digits01[p1], '-', - digits10[p2], digits01[p2], '-', - digits10[p3], digits01[p3], - ) - if length == 10 { - return dst, nil - } - if len(src) == 4 { - return append(dst, zeroDateTime[10:length]...), nil - } - dst = append(dst, ' ') - p1 = src[4] // hour - src = src[5:] - - // p1 is 2-digit hour, src is after hour - p2, p3 = src[0], src[1] - dst = append(dst, - digits10[p1], digits01[p1], ':', - digits10[p2], digits01[p2], ':', - digits10[p3], digits01[p3], - ) - return appendMicrosecs(dst, src[2:], int(length)-20), nil -} - -func formatBinaryTime(src []byte, length uint8) (driver.Value, error) { - // length expects the deterministic length of the zero value, - // negative time and 100+ hours are automatically added if needed - if len(src) == 0 { - return zeroDateTime[11 : 11+length], nil - } - var dst []byte // return value - - switch length { - case - 8, // time (can be up to 10 when negative and 100+ hours) - 10, 11, 12, 13, 14, 15: // time with fractional seconds - default: - return nil, fmt.Errorf("illegal TIME length %d", length) - } - switch len(src) { - case 8, 12: - default: - return nil, fmt.Errorf("invalid TIME packet length %d", len(src)) - } - // +2 to enable negative time and 100+ hours - dst = make([]byte, 0, length+2) - if src[0] == 1 { - dst = append(dst, '-') - } - days := binary.LittleEndian.Uint32(src[1:5]) - hours := int64(days)*24 + int64(src[5]) - - if hours >= 100 { - dst = strconv.AppendInt(dst, hours, 10) - } else { - dst = append(dst, digits10[hours], digits01[hours]) - } - - min, sec := src[6], src[7] - dst = append(dst, ':', - digits10[min], digits01[min], ':', - digits10[sec], digits01[sec], - ) - return appendMicrosecs(dst, src[8:], int(length)-9), nil -} - -/****************************************************************************** -* Convert from and to bytes * -******************************************************************************/ - -func uint64ToBytes(n uint64) []byte { - return []byte{ - byte(n), - byte(n >> 8), - byte(n >> 16), - byte(n >> 24), - byte(n >> 32), - byte(n >> 40), - byte(n >> 48), - byte(n >> 56), - } -} - -func uint64ToString(n uint64) []byte { - var a [20]byte - i := 20 - - // U+0030 = 0 - // ... - // U+0039 = 9 - - var q uint64 - for n >= 10 { - i-- - q = n / 10 - a[i] = uint8(n-q*10) + 0x30 - n = q - } - - i-- - a[i] = uint8(n) + 0x30 - - return a[i:] -} - -// treats string value as unsigned integer representation -func stringToInt(b []byte) int { - val := 0 - for i := range b { - val *= 10 - val += int(b[i] - 0x30) - } - return val -} - -// returns the string read as a bytes slice, whether the value is NULL, -// the number of bytes read and an error, in case the string is longer than -// the input slice -func readLengthEncodedString(b []byte) ([]byte, bool, int, error) { - // Get length - num, isNull, n := readLengthEncodedInteger(b) - if num < 1 { - return b[n:n], isNull, n, nil - } - - n += int(num) - - // Check data length - if len(b) >= n { - return b[n-int(num) : n : n], false, n, nil - } - return nil, false, n, io.EOF -} - -// returns the number of bytes skipped and an error, in case the string is -// longer than the input slice -func skipLengthEncodedString(b []byte) (int, error) { - // Get length - num, _, n := readLengthEncodedInteger(b) - if num < 1 { - return n, nil - } - - n += int(num) - - // Check data length - if len(b) >= n { - return n, nil - } - return n, io.EOF -} - -// returns the number read, whether the value is NULL and the number of bytes read -func readLengthEncodedInteger(b []byte) (uint64, bool, int) { - // See issue #349 - if len(b) == 0 { - return 0, true, 1 - } - - switch b[0] { - // 251: NULL - case 0xfb: - return 0, true, 1 - - // 252: value of following 2 - case 0xfc: - return uint64(b[1]) | uint64(b[2])<<8, false, 3 - - // 253: value of following 3 - case 0xfd: - return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4 - - // 254: value of following 8 - case 0xfe: - return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 | - uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 | - uint64(b[7])<<48 | uint64(b[8])<<56, - false, 9 - } - - // 0-250: value of first byte - return uint64(b[0]), false, 1 -} - -// encodes a uint64 value and appends it to the given bytes slice -func appendLengthEncodedInteger(b []byte, n uint64) []byte { - switch { - case n <= 250: - return append(b, byte(n)) - - case n <= 0xffff: - return append(b, 0xfc, byte(n), byte(n>>8)) - - case n <= 0xffffff: - return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) - } - return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), - byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) -} - -func appendLengthEncodedString(b []byte, s string) []byte { - b = appendLengthEncodedInteger(b, uint64(len(s))) - return append(b, s...) -} - -// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize. -// If cap(buf) is not enough, reallocate new buffer. -func reserveBuffer(buf []byte, appendSize int) []byte { - newSize := len(buf) + appendSize - if cap(buf) < newSize { - // Grow buffer exponentially - newBuf := make([]byte, len(buf)*2+appendSize) - copy(newBuf, buf) - buf = newBuf - } - return buf[:newSize] -} - -// escapeBytesBackslash escapes []byte with backslashes (\) -// This escapes the contents of a string (provided as []byte) by adding backslashes before special -// characters, and turning others into specific escape sequences, such as -// turning newlines into \n and null bytes into \0. -// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932 -func escapeBytesBackslash(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for _, c := range v { - switch c { - case '\x00': - buf[pos+1] = '0' - buf[pos] = '\\' - pos += 2 - case '\n': - buf[pos+1] = 'n' - buf[pos] = '\\' - pos += 2 - case '\r': - buf[pos+1] = 'r' - buf[pos] = '\\' - pos += 2 - case '\x1a': - buf[pos+1] = 'Z' - buf[pos] = '\\' - pos += 2 - case '\'': - buf[pos+1] = '\'' - buf[pos] = '\\' - pos += 2 - case '"': - buf[pos+1] = '"' - buf[pos] = '\\' - pos += 2 - case '\\': - buf[pos+1] = '\\' - buf[pos] = '\\' - pos += 2 - default: - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeStringBackslash is similar to escapeBytesBackslash but for string. -func escapeStringBackslash(buf []byte, v string) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - switch c { - case '\x00': - buf[pos+1] = '0' - buf[pos] = '\\' - pos += 2 - case '\n': - buf[pos+1] = 'n' - buf[pos] = '\\' - pos += 2 - case '\r': - buf[pos+1] = 'r' - buf[pos] = '\\' - pos += 2 - case '\x1a': - buf[pos+1] = 'Z' - buf[pos] = '\\' - pos += 2 - case '\'': - buf[pos+1] = '\'' - buf[pos] = '\\' - pos += 2 - case '"': - buf[pos+1] = '"' - buf[pos] = '\\' - pos += 2 - case '\\': - buf[pos+1] = '\\' - buf[pos] = '\\' - pos += 2 - default: - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeBytesQuotes escapes apostrophes in []byte by doubling them up. -// This escapes the contents of a string by doubling up any apostrophes that -// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in -// effect on the server. -// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038 -func escapeBytesQuotes(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for _, c := range v { - if c == '\'' { - buf[pos+1] = '\'' - buf[pos] = '\'' - pos += 2 - } else { - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeStringQuotes is similar to escapeBytesQuotes but for string. -func escapeStringQuotes(buf []byte, v string) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - if c == '\'' { - buf[pos+1] = '\'' - buf[pos] = '\'' - pos += 2 - } else { - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -// noCopy may be embedded into structs which must not be copied -// after the first use. -// -// See https://github.com/golang/go/issues/8005#issuecomment-190753527 -// for details. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} - -// Unlock is a no-op used by -copylocks checker from `go vet`. -// noCopy should implement sync.Locker from Go 1.11 -// https://github.com/golang/go/commit/c2eba53e7f80df21d51285879d51ab81bcfbf6bc -// https://github.com/golang/go/issues/26165 -func (*noCopy) Unlock() {} - -// atomicError is a wrapper for atomically accessed error values -type atomicError struct { - _ noCopy - value atomic.Value -} - -// Set sets the error value regardless of the previous value. -// The value must not be nil -func (ae *atomicError) Set(value error) { - ae.value.Store(value) -} - -// Value returns the current error value -func (ae *atomicError) Value() error { - if v := ae.value.Load(); v != nil { - // this will panic if the value doesn't implement the error interface - return v.(error) - } - return nil -} - -func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { - dargs := make([]driver.Value, len(named)) - for n, param := range named { - if len(param.Name) > 0 { - // TODO: support the use of Named Parameters #561 - return nil, errors.New("mysql: driver does not support the use of Named Parameters") - } - dargs[n] = param.Value - } - return dargs, nil -} - -func mapIsolationLevel(level driver.IsolationLevel) (string, error) { - switch sql.IsolationLevel(level) { - case sql.LevelRepeatableRead: - return "REPEATABLE READ", nil - case sql.LevelReadCommitted: - return "READ COMMITTED", nil - case sql.LevelReadUncommitted: - return "READ UNCOMMITTED", nil - case sql.LevelSerializable: - return "SERIALIZABLE", nil - default: - return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) - } -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/.editorconfig b/vendor/github.com/go-viper/mapstructure/v2/.editorconfig deleted file mode 100644 index 1f664d1..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 4 -indent_style = space -insert_final_newline = true -trim_trailing_whitespace = true - -[*.go] -indent_style = tab - -[{Makefile,*.mk}] -indent_style = tab - -[*.nix] -indent_size = 2 diff --git a/vendor/github.com/go-viper/mapstructure/v2/.envrc b/vendor/github.com/go-viper/mapstructure/v2/.envrc deleted file mode 100644 index 2e0f9f5..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/.envrc +++ /dev/null @@ -1,4 +0,0 @@ -if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then - source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4=" -fi -use flake . --impure diff --git a/vendor/github.com/go-viper/mapstructure/v2/.gitignore b/vendor/github.com/go-viper/mapstructure/v2/.gitignore deleted file mode 100644 index 470e7ca..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/.devenv/ -/.direnv/ -/.pre-commit-config.yaml -/bin/ -/build/ -/var/ diff --git a/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml b/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml deleted file mode 100644 index 763143a..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml +++ /dev/null @@ -1,23 +0,0 @@ -run: - timeout: 5m - -linters-settings: - gci: - sections: - - standard - - default - - prefix(github.com/go-viper/mapstructure) - golint: - min-confidence: 0 - goimports: - local-prefixes: github.com/go-viper/maptstructure - -linters: - disable-all: true - enable: - - gci - - gofmt - - gofumpt - - goimports - - staticcheck - # - stylecheck diff --git a/vendor/github.com/go-viper/mapstructure/v2/CHANGELOG.md b/vendor/github.com/go-viper/mapstructure/v2/CHANGELOG.md deleted file mode 100644 index afd44e5..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/CHANGELOG.md +++ /dev/null @@ -1,104 +0,0 @@ -> [!WARNING] -> As of v2 of this library, change log can be found in GitHub releases. - -## 1.5.1 - -* Wrap errors so they're compatible with `errors.Is` and `errors.As` [GH-282] -* Fix map of slices not decoding properly in certain cases. [GH-266] - -## 1.5.0 - -* New option `IgnoreUntaggedFields` to ignore decoding to any fields - without `mapstructure` (or the configured tag name) set [GH-277] -* New option `ErrorUnset` which makes it an error if any fields - in a target struct are not set by the decoding process. [GH-225] -* New function `OrComposeDecodeHookFunc` to help compose decode hooks. [GH-240] -* Decoding to slice from array no longer crashes [GH-265] -* Decode nested struct pointers to map [GH-271] -* Fix issue where `,squash` was ignored if `Squash` option was set. [GH-280] -* Fix issue where fields with `,omitempty` would sometimes decode - into a map with an empty string key [GH-281] - -## 1.4.3 - -* Fix cases where `json.Number` didn't decode properly [GH-261] - -## 1.4.2 - -* Custom name matchers to support any sort of casing, formatting, etc. for - field names. [GH-250] -* Fix possible panic in ComposeDecodeHookFunc [GH-251] - -## 1.4.1 - -* Fix regression where `*time.Time` value would be set to empty and not be sent - to decode hooks properly [GH-232] - -## 1.4.0 - -* A new decode hook type `DecodeHookFuncValue` has been added that has - access to the full values. [GH-183] -* Squash is now supported with embedded fields that are struct pointers [GH-205] -* Empty strings will convert to 0 for all numeric types when weakly decoding [GH-206] - -## 1.3.3 - -* Decoding maps from maps creates a settable value for decode hooks [GH-203] - -## 1.3.2 - -* Decode into interface type with a struct value is supported [GH-187] - -## 1.3.1 - -* Squash should only squash embedded structs. [GH-194] - -## 1.3.0 - -* Added `",omitempty"` support. This will ignore zero values in the source - structure when encoding. [GH-145] - -## 1.2.3 - -* Fix duplicate entries in Keys list with pointer values. [GH-185] - -## 1.2.2 - -* Do not add unsettable (unexported) values to the unused metadata key - or "remain" value. [GH-150] - -## 1.2.1 - -* Go modules checksum mismatch fix - -## 1.2.0 - -* Added support to capture unused values in a field using the `",remain"` value - in the mapstructure tag. There is an example to showcase usage. -* Added `DecoderConfig` option to always squash embedded structs -* `json.Number` can decode into `uint` types -* Empty slices are preserved and not replaced with nil slices -* Fix panic that can occur in when decoding a map into a nil slice of structs -* Improved package documentation for godoc - -## 1.1.2 - -* Fix error when decode hook decodes interface implementation into interface - type. [GH-140] - -## 1.1.1 - -* Fix panic that can happen in `decodePtr` - -## 1.1.0 - -* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133] -* Support struct to struct decoding [GH-137] -* If source map value is nil, then destination map value is nil (instead of empty) -* If source slice value is nil, then destination slice value is nil (instead of empty) -* If source pointer is nil, then destination pointer is set to nil (instead of - allocated zero value of type) - -## 1.0.0 - -* Initial tagged stable release. diff --git a/vendor/github.com/go-viper/mapstructure/v2/LICENSE b/vendor/github.com/go-viper/mapstructure/v2/LICENSE deleted file mode 100644 index f9c841a..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Mitchell Hashimoto - -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. diff --git a/vendor/github.com/go-viper/mapstructure/v2/README.md b/vendor/github.com/go-viper/mapstructure/v2/README.md deleted file mode 100644 index dd5ec69..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# mapstructure - -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/go-viper/mapstructure/ci.yaml?branch=main&style=flat-square)](https://github.com/go-viper/mapstructure/actions?query=workflow%3ACI) -[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2) -![Go Version](https://img.shields.io/badge/go%20version-%3E=1.18-61CFDD.svg?style=flat-square) - -mapstructure is a Go library for decoding generic map values to structures -and vice versa, while providing helpful error handling. - -This library is most useful when decoding values from some data stream (JSON, -Gob, etc.) where you don't _quite_ know the structure of the underlying data -until you read a part of it. You can therefore read a `map[string]interface{}` -and use this library to decode it into the proper underlying native Go -structure. - -## Installation - -```shell -go get github.com/go-viper/mapstructure/v2 -``` - -## Migrating from `github.com/mitchellh/mapstructure` - -[@mitchehllh](https://github.com/mitchellh) announced his intent to archive some of his unmaintained projects (see [here](https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc) and [here](https://github.com/mitchellh/mapstructure/issues/349)). This is a repository achieved the "blessed fork" status. - -You can migrate to this package by changing your import paths in your Go files to `github.com/go-viper/mapstructure/v2`. -The API is the same, so you don't need to change anything else. - -Here is a script that can help you with the migration: - -```shell -sed -i 's/github.com\/mitchellh\/mapstructure/github.com\/go-viper\/mapstructure\/v2/g' $(find . -type f -name '*.go') -``` - -If you need more time to migrate your code, that is absolutely fine. - -Some of the latest fixes are backported to the v1 release branch of this package, so you can use the Go modules `replace` feature until you are ready to migrate: - -```shell -replace github.com/mitchellh/mapstructure => github.com/go-viper/mapstructure v1.6.0 -``` - -## Usage & Example - -For usage and examples see the [documentation](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2). - -The `Decode` function has examples associated with it there. - -## But Why?! - -Go offers fantastic standard libraries for decoding formats such as JSON. -The standard method is to have a struct pre-created, and populate that struct -from the bytes of the encoded format. This is great, but the problem is if -you have configuration or an encoding that changes slightly depending on -specific fields. For example, consider this JSON: - -```json -{ - "type": "person", - "name": "Mitchell" -} -``` - -Perhaps we can't populate a specific structure without first reading -the "type" field from the JSON. We could always do two passes over the -decoding of the JSON (reading the "type" first, and the rest later). -However, it is much simpler to just decode this into a `map[string]interface{}` -structure, read the "type" key, then use something like this library -to decode it into the proper structure. - -## Credits - -Mapstructure was originally created by [@mitchellh](https://github.com/mitchellh). -This is a maintained fork of the original library. - -Read more about the reasons for the fork [here](https://github.com/mitchellh/mapstructure/issues/349). - -## License - -The project is licensed under the [MIT License](LICENSE). diff --git a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go deleted file mode 100644 index 1f3c69d..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go +++ /dev/null @@ -1,630 +0,0 @@ -package mapstructure - -import ( - "encoding" - "errors" - "fmt" - "net" - "net/netip" - "net/url" - "reflect" - "strconv" - "strings" - "time" -) - -// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns -// it into the proper DecodeHookFunc type, such as DecodeHookFuncType. -func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { - // Create variables here so we can reference them with the reflect pkg - var f1 DecodeHookFuncType - var f2 DecodeHookFuncKind - var f3 DecodeHookFuncValue - - // Fill in the variables into this interface and the rest is done - // automatically using the reflect package. - potential := []interface{}{f1, f2, f3} - - v := reflect.ValueOf(h) - vt := v.Type() - for _, raw := range potential { - pt := reflect.ValueOf(raw).Type() - if vt.ConvertibleTo(pt) { - return v.Convert(pt).Interface() - } - } - - return nil -} - -// cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns -// it into a closure to be used directly -// if the type fails to convert we return a closure always erroring to keep the previous behaviour -func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (interface{}, error) { - switch f := typedDecodeHook(raw).(type) { - case DecodeHookFuncType: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { - return f(from.Type(), to.Type(), from.Interface()) - } - case DecodeHookFuncKind: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { - return f(from.Kind(), to.Kind(), from.Interface()) - } - case DecodeHookFuncValue: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { - return f(from, to) - } - default: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { - return nil, errors.New("invalid decode hook signature") - } - } -} - -// DecodeHookExec executes the given decode hook. This should be used -// since it'll naturally degrade to the older backwards compatible DecodeHookFunc -// that took reflect.Kind instead of reflect.Type. -func DecodeHookExec( - raw DecodeHookFunc, - from reflect.Value, to reflect.Value, -) (interface{}, error) { - switch f := typedDecodeHook(raw).(type) { - case DecodeHookFuncType: - return f(from.Type(), to.Type(), from.Interface()) - case DecodeHookFuncKind: - return f(from.Kind(), to.Kind(), from.Interface()) - case DecodeHookFuncValue: - return f(from, to) - default: - return nil, errors.New("invalid decode hook signature") - } -} - -// ComposeDecodeHookFunc creates a single DecodeHookFunc that -// automatically composes multiple DecodeHookFuncs. -// -// The composed funcs are called in order, with the result of the -// previous transformation. -func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { - cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(fs)) - for _, f := range fs { - cached = append(cached, cachedDecodeHook(f)) - } - return func(f reflect.Value, t reflect.Value) (interface{}, error) { - var err error - data := f.Interface() - - newFrom := f - for _, c := range cached { - data, err = c(newFrom, t) - if err != nil { - return nil, err - } - newFrom = reflect.ValueOf(data) - } - - return data, nil - } -} - -// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned. -// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages. -func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc { - cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(ff)) - for _, f := range ff { - cached = append(cached, cachedDecodeHook(f)) - } - return func(a, b reflect.Value) (interface{}, error) { - var allErrs string - var out interface{} - var err error - - for _, c := range cached { - out, err = c(a, b) - if err != nil { - allErrs += err.Error() + "\n" - continue - } - - return out, nil - } - - return nil, errors.New(allErrs) - } -} - -// StringToSliceHookFunc returns a DecodeHookFunc that converts -// string to []string by splitting on the given sep. -func StringToSliceHookFunc(sep string) DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.SliceOf(f) { - return data, nil - } - - raw := data.(string) - if raw == "" { - return []string{}, nil - } - - return strings.Split(raw, sep), nil - } -} - -// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts -// strings to time.Duration. -func StringToTimeDurationHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(time.Duration(5)) { - return data, nil - } - - // Convert it by parsing - return time.ParseDuration(data.(string)) - } -} - -// StringToURLHookFunc returns a DecodeHookFunc that converts -// strings to *url.URL. -func StringToURLHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(&url.URL{}) { - return data, nil - } - - // Convert it by parsing - return url.Parse(data.(string)) - } -} - -// StringToIPHookFunc returns a DecodeHookFunc that converts -// strings to net.IP -func StringToIPHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(net.IP{}) { - return data, nil - } - - // Convert it by parsing - ip := net.ParseIP(data.(string)) - if ip == nil { - return net.IP{}, fmt.Errorf("failed parsing ip %v", data) - } - - return ip, nil - } -} - -// StringToIPNetHookFunc returns a DecodeHookFunc that converts -// strings to net.IPNet -func StringToIPNetHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(net.IPNet{}) { - return data, nil - } - - // Convert it by parsing - _, net, err := net.ParseCIDR(data.(string)) - return net, err - } -} - -// StringToTimeHookFunc returns a DecodeHookFunc that converts -// strings to time.Time. -func StringToTimeHookFunc(layout string) DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(time.Time{}) { - return data, nil - } - - // Convert it by parsing - return time.Parse(layout, data.(string)) - } -} - -// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to -// the decoder. -// -// Note that this is significantly different from the WeaklyTypedInput option -// of the DecoderConfig. -func WeaklyTypedHook( - f reflect.Kind, - t reflect.Kind, - data interface{}, -) (interface{}, error) { - dataVal := reflect.ValueOf(data) - switch t { - case reflect.String: - switch f { - case reflect.Bool: - if dataVal.Bool() { - return "1", nil - } - return "0", nil - case reflect.Float32: - return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil - case reflect.Int: - return strconv.FormatInt(dataVal.Int(), 10), nil - case reflect.Slice: - dataType := dataVal.Type() - elemKind := dataType.Elem().Kind() - if elemKind == reflect.Uint8 { - return string(dataVal.Interface().([]uint8)), nil - } - case reflect.Uint: - return strconv.FormatUint(dataVal.Uint(), 10), nil - } - } - - return data, nil -} - -func RecursiveStructToMapHookFunc() DecodeHookFunc { - return func(f reflect.Value, t reflect.Value) (interface{}, error) { - if f.Kind() != reflect.Struct { - return f.Interface(), nil - } - - var i interface{} = struct{}{} - if t.Type() != reflect.TypeOf(&i).Elem() { - return f.Interface(), nil - } - - m := make(map[string]interface{}) - t.Set(reflect.ValueOf(m)) - - return f.Interface(), nil - } -} - -// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies -// strings to the UnmarshalText function, when the target type -// implements the encoding.TextUnmarshaler interface -func TextUnmarshallerHookFunc() DecodeHookFuncType { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - result := reflect.New(t).Interface() - unmarshaller, ok := result.(encoding.TextUnmarshaler) - if !ok { - return data, nil - } - str, ok := data.(string) - if !ok { - str = reflect.Indirect(reflect.ValueOf(&data)).Elem().String() - } - if err := unmarshaller.UnmarshalText([]byte(str)); err != nil { - return nil, err - } - return result, nil - } -} - -// StringToNetIPAddrHookFunc returns a DecodeHookFunc that converts -// strings to netip.Addr. -func StringToNetIPAddrHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(netip.Addr{}) { - return data, nil - } - - // Convert it by parsing - return netip.ParseAddr(data.(string)) - } -} - -// StringToNetIPAddrPortHookFunc returns a DecodeHookFunc that converts -// strings to netip.AddrPort. -func StringToNetIPAddrPortHookFunc() DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}, - ) (interface{}, error) { - if f.Kind() != reflect.String { - return data, nil - } - if t != reflect.TypeOf(netip.AddrPort{}) { - return data, nil - } - - // Convert it by parsing - return netip.ParseAddrPort(data.(string)) - } -} - -// StringToBasicTypeHookFunc returns a DecodeHookFunc that converts -// strings to basic types. -// int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64, bool, byte, rune, complex64, complex128 -func StringToBasicTypeHookFunc() DecodeHookFunc { - return ComposeDecodeHookFunc( - StringToInt8HookFunc(), - StringToUint8HookFunc(), - StringToInt16HookFunc(), - StringToUint16HookFunc(), - StringToInt32HookFunc(), - StringToUint32HookFunc(), - StringToInt64HookFunc(), - StringToUint64HookFunc(), - StringToIntHookFunc(), - StringToUintHookFunc(), - StringToFloat32HookFunc(), - StringToFloat64HookFunc(), - StringToBoolHookFunc(), - // byte and rune are aliases for uint8 and int32 respectively - // StringToByteHookFunc(), - // StringToRuneHookFunc(), - StringToComplex64HookFunc(), - StringToComplex128HookFunc(), - ) -} - -// StringToInt8HookFunc returns a DecodeHookFunc that converts -// strings to int8. -func StringToInt8HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Int8 { - return data, nil - } - - // Convert it by parsing - i64, err := strconv.ParseInt(data.(string), 0, 8) - return int8(i64), err - } -} - -// StringToUint8HookFunc returns a DecodeHookFunc that converts -// strings to uint8. -func StringToUint8HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Uint8 { - return data, nil - } - - // Convert it by parsing - u64, err := strconv.ParseUint(data.(string), 0, 8) - return uint8(u64), err - } -} - -// StringToInt16HookFunc returns a DecodeHookFunc that converts -// strings to int16. -func StringToInt16HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Int16 { - return data, nil - } - - // Convert it by parsing - i64, err := strconv.ParseInt(data.(string), 0, 16) - return int16(i64), err - } -} - -// StringToUint16HookFunc returns a DecodeHookFunc that converts -// strings to uint16. -func StringToUint16HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Uint16 { - return data, nil - } - - // Convert it by parsing - u64, err := strconv.ParseUint(data.(string), 0, 16) - return uint16(u64), err - } -} - -// StringToInt32HookFunc returns a DecodeHookFunc that converts -// strings to int32. -func StringToInt32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Int32 { - return data, nil - } - - // Convert it by parsing - i64, err := strconv.ParseInt(data.(string), 0, 32) - return int32(i64), err - } -} - -// StringToUint32HookFunc returns a DecodeHookFunc that converts -// strings to uint32. -func StringToUint32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Uint32 { - return data, nil - } - - // Convert it by parsing - u64, err := strconv.ParseUint(data.(string), 0, 32) - return uint32(u64), err - } -} - -// StringToInt64HookFunc returns a DecodeHookFunc that converts -// strings to int64. -func StringToInt64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Int64 { - return data, nil - } - - // Convert it by parsing - return strconv.ParseInt(data.(string), 0, 64) - } -} - -// StringToUint64HookFunc returns a DecodeHookFunc that converts -// strings to uint64. -func StringToUint64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Uint64 { - return data, nil - } - - // Convert it by parsing - return strconv.ParseUint(data.(string), 0, 64) - } -} - -// StringToIntHookFunc returns a DecodeHookFunc that converts -// strings to int. -func StringToIntHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Int { - return data, nil - } - - // Convert it by parsing - i64, err := strconv.ParseInt(data.(string), 0, 0) - return int(i64), err - } -} - -// StringToUintHookFunc returns a DecodeHookFunc that converts -// strings to uint. -func StringToUintHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Uint { - return data, nil - } - - // Convert it by parsing - u64, err := strconv.ParseUint(data.(string), 0, 0) - return uint(u64), err - } -} - -// StringToFloat32HookFunc returns a DecodeHookFunc that converts -// strings to float32. -func StringToFloat32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Float32 { - return data, nil - } - - // Convert it by parsing - f64, err := strconv.ParseFloat(data.(string), 32) - return float32(f64), err - } -} - -// StringToFloat64HookFunc returns a DecodeHookFunc that converts -// strings to float64. -func StringToFloat64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Float64 { - return data, nil - } - - // Convert it by parsing - return strconv.ParseFloat(data.(string), 64) - } -} - -// StringToBoolHookFunc returns a DecodeHookFunc that converts -// strings to bool. -func StringToBoolHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Bool { - return data, nil - } - - // Convert it by parsing - return strconv.ParseBool(data.(string)) - } -} - -// StringToByteHookFunc returns a DecodeHookFunc that converts -// strings to byte. -func StringToByteHookFunc() DecodeHookFunc { - return StringToUint8HookFunc() -} - -// StringToRuneHookFunc returns a DecodeHookFunc that converts -// strings to rune. -func StringToRuneHookFunc() DecodeHookFunc { - return StringToInt32HookFunc() -} - -// StringToComplex64HookFunc returns a DecodeHookFunc that converts -// strings to complex64. -func StringToComplex64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Complex64 { - return data, nil - } - - // Convert it by parsing - c128, err := strconv.ParseComplex(data.(string), 64) - return complex64(c128), err - } -} - -// StringToComplex128HookFunc returns a DecodeHookFunc that converts -// strings to complex128. -func StringToComplex128HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if f.Kind() != reflect.String || t.Kind() != reflect.Complex128 { - return data, nil - } - - // Convert it by parsing - return strconv.ParseComplex(data.(string), 128) - } -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/flake.lock b/vendor/github.com/go-viper/mapstructure/v2/flake.lock deleted file mode 100644 index 4bea815..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/flake.lock +++ /dev/null @@ -1,472 +0,0 @@ -{ - "nodes": { - "cachix": { - "inputs": { - "devenv": "devenv_2", - "flake-compat": [ - "devenv", - "flake-compat" - ], - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "pre-commit-hooks": [ - "devenv", - "pre-commit-hooks" - ] - }, - "locked": { - "lastModified": 1712055811, - "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", - "owner": "cachix", - "repo": "cachix", - "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "cachix", - "type": "github" - } - }, - "devenv": { - "inputs": { - "cachix": "cachix", - "flake-compat": "flake-compat_2", - "nix": "nix_2", - "nixpkgs": "nixpkgs_2", - "pre-commit-hooks": "pre-commit-hooks" - }, - "locked": { - "lastModified": 1717245169, - "narHash": "sha256-+mW3rTBjGU8p1THJN0lX/Dd/8FbnF+3dB+mJuSaxewE=", - "owner": "cachix", - "repo": "devenv", - "rev": "c3f9f053c077c6f88a3de5276d9178c62baa3fc3", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "devenv_2": { - "inputs": { - "flake-compat": [ - "devenv", - "cachix", - "flake-compat" - ], - "nix": "nix", - "nixpkgs": "nixpkgs", - "poetry2nix": "poetry2nix", - "pre-commit-hooks": [ - "devenv", - "cachix", - "pre-commit-hooks" - ] - }, - "locked": { - "lastModified": 1708704632, - "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", - "owner": "cachix", - "repo": "devenv", - "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "python-rewrite", - "repo": "devenv", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_2": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1717285511, - "narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1689068808, - "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "devenv", - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nix": { - "inputs": { - "flake-compat": "flake-compat", - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "nixpkgs" - ], - "nixpkgs-regression": "nixpkgs-regression" - }, - "locked": { - "lastModified": 1712911606, - "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", - "owner": "domenkozar", - "repo": "nix", - "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", - "type": "github" - }, - "original": { - "owner": "domenkozar", - "ref": "devenv-2.21", - "repo": "nix", - "type": "github" - } - }, - "nix-github-actions": { - "inputs": { - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1688870561, - "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", - "owner": "nix-community", - "repo": "nix-github-actions", - "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nix-github-actions", - "type": "github" - } - }, - "nix_2": { - "inputs": { - "flake-compat": [ - "devenv", - "flake-compat" - ], - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "nixpkgs-regression": "nixpkgs-regression_2" - }, - "locked": { - "lastModified": 1712911606, - "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", - "owner": "domenkozar", - "repo": "nix", - "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", - "type": "github" - }, - "original": { - "owner": "domenkozar", - "ref": "devenv-2.21", - "repo": "nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1692808169, - "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1717284937, - "narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" - } - }, - "nixpkgs-regression": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "nixpkgs-regression_2": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1710695816, - "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "614b4613980a522ba49f0d194531beddbb7220d3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1713361204, - "narHash": "sha256-TA6EDunWTkc5FvDCqU3W2T3SFn0gRZqh6D/hJnM02MM=", - "owner": "cachix", - "repo": "devenv-nixpkgs", - "rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "rolling", - "repo": "devenv-nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1717112898, - "narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "poetry2nix": { - "inputs": { - "flake-utils": "flake-utils", - "nix-github-actions": "nix-github-actions", - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1692876271, - "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", - "owner": "nix-community", - "repo": "poetry2nix", - "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "poetry2nix", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": [ - "devenv", - "flake-compat" - ], - "flake-utils": "flake-utils_2", - "gitignore": "gitignore", - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1713775815, - "narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs_3" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/flake.nix b/vendor/github.com/go-viper/mapstructure/v2/flake.nix deleted file mode 100644 index 4ed0f53..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/flake.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-parts.url = "github:hercules-ci/flake-parts"; - devenv.url = "github:cachix/devenv"; - }; - - outputs = inputs@{ flake-parts, ... }: - flake-parts.lib.mkFlake { inherit inputs; } { - imports = [ - inputs.devenv.flakeModule - ]; - - systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" ]; - - perSystem = { config, self', inputs', pkgs, system, ... }: rec { - devenv.shells = { - default = { - languages = { - go.enable = true; - }; - - pre-commit.hooks = { - nixpkgs-fmt.enable = true; - }; - - packages = with pkgs; [ - golangci-lint - ]; - - # https://github.com/cachix/devenv/issues/528#issuecomment-1556108767 - containers = pkgs.lib.mkForce { }; - }; - - ci = devenv.shells.default; - }; - }; - }; -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/internal/errors/errors.go b/vendor/github.com/go-viper/mapstructure/v2/internal/errors/errors.go deleted file mode 100644 index d1c15e4..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/internal/errors/errors.go +++ /dev/null @@ -1,11 +0,0 @@ -package errors - -import "errors" - -func New(text string) error { - return errors.New(text) -} - -func As(err error, target interface{}) bool { - return errors.As(err, target) -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/internal/errors/join.go b/vendor/github.com/go-viper/mapstructure/v2/internal/errors/join.go deleted file mode 100644 index d74e3a0..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/internal/errors/join.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build go1.20 - -package errors - -import "errors" - -func Join(errs ...error) error { - return errors.Join(errs...) -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/internal/errors/join_go1_19.go b/vendor/github.com/go-viper/mapstructure/v2/internal/errors/join_go1_19.go deleted file mode 100644 index 700b402..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/internal/errors/join_go1_19.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build !go1.20 - -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package errors - -// Join returns an error that wraps the given errors. -// Any nil error values are discarded. -// Join returns nil if every value in errs is nil. -// The error formats as the concatenation of the strings obtained -// by calling the Error method of each element of errs, with a newline -// between each string. -// -// A non-nil error returned by Join implements the Unwrap() []error method. -func Join(errs ...error) error { - n := 0 - for _, err := range errs { - if err != nil { - n++ - } - } - if n == 0 { - return nil - } - e := &joinError{ - errs: make([]error, 0, n), - } - for _, err := range errs { - if err != nil { - e.errs = append(e.errs, err) - } - } - return e -} - -type joinError struct { - errs []error -} - -func (e *joinError) Error() string { - // Since Join returns nil if every value in errs is nil, - // e.errs cannot be empty. - if len(e.errs) == 1 { - return e.errs[0].Error() - } - - b := []byte(e.errs[0].Error()) - for _, err := range e.errs[1:] { - b = append(b, '\n') - b = append(b, err.Error()...) - } - // At this point, b has at least one byte '\n'. - // return unsafe.String(&b[0], len(b)) - return string(b) -} - -func (e *joinError) Unwrap() []error { - return e.errs -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go deleted file mode 100644 index e77e63b..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go +++ /dev/null @@ -1,1620 +0,0 @@ -// Package mapstructure exposes functionality to convert one arbitrary -// Go type into another, typically to convert a map[string]interface{} -// into a native Go structure. -// -// The Go structure can be arbitrarily complex, containing slices, -// other structs, etc. and the decoder will properly decode nested -// maps and so on into the proper structures in the native Go struct. -// See the examples to see what the decoder is capable of. -// -// The simplest function to start with is Decode. -// -// # Field Tags -// -// When decoding to a struct, mapstructure will use the field name by -// default to perform the mapping. For example, if a struct has a field -// "Username" then mapstructure will look for a key in the source value -// of "username" (case insensitive). -// -// type User struct { -// Username string -// } -// -// You can change the behavior of mapstructure by using struct tags. -// The default struct tag that mapstructure looks for is "mapstructure" -// but you can customize it using DecoderConfig. -// -// # Renaming Fields -// -// To rename the key that mapstructure looks for, use the "mapstructure" -// tag and set a value directly. For example, to change the "username" example -// above to "user": -// -// type User struct { -// Username string `mapstructure:"user"` -// } -// -// # Embedded Structs and Squashing -// -// Embedded structs are treated as if they're another field with that name. -// By default, the two structs below are equivalent when decoding with -// mapstructure: -// -// type Person struct { -// Name string -// } -// -// type Friend struct { -// Person -// } -// -// type Friend struct { -// Person Person -// } -// -// This would require an input that looks like below: -// -// map[string]interface{}{ -// "person": map[string]interface{}{"name": "alice"}, -// } -// -// If your "person" value is NOT nested, then you can append ",squash" to -// your tag value and mapstructure will treat it as if the embedded struct -// were part of the struct directly. Example: -// -// type Friend struct { -// Person `mapstructure:",squash"` -// } -// -// Now the following input would be accepted: -// -// map[string]interface{}{ -// "name": "alice", -// } -// -// When decoding from a struct to a map, the squash tag squashes the struct -// fields into a single map. Using the example structs from above: -// -// Friend{Person: Person{Name: "alice"}} -// -// Will be decoded into a map: -// -// map[string]interface{}{ -// "name": "alice", -// } -// -// DecoderConfig has a field that changes the behavior of mapstructure -// to always squash embedded structs. -// -// # Remainder Values -// -// If there are any unmapped keys in the source value, mapstructure by -// default will silently ignore them. You can error by setting ErrorUnused -// in DecoderConfig. If you're using Metadata you can also maintain a slice -// of the unused keys. -// -// You can also use the ",remain" suffix on your tag to collect all unused -// values in a map. The field with this tag MUST be a map type and should -// probably be a "map[string]interface{}" or "map[interface{}]interface{}". -// See example below: -// -// type Friend struct { -// Name string -// Other map[string]interface{} `mapstructure:",remain"` -// } -// -// Given the input below, Other would be populated with the other -// values that weren't used (everything but "name"): -// -// map[string]interface{}{ -// "name": "bob", -// "address": "123 Maple St.", -// } -// -// # Omit Empty Values -// -// When decoding from a struct to any other value, you may use the -// ",omitempty" suffix on your tag to omit that value if it equates to -// the zero value. The zero value of all types is specified in the Go -// specification. -// -// For example, the zero type of a numeric type is zero ("0"). If the struct -// field value is zero and a numeric type, the field is empty, and it won't -// be encoded into the destination type. -// -// type Source struct { -// Age int `mapstructure:",omitempty"` -// } -// -// # Unexported fields -// -// Since unexported (private) struct fields cannot be set outside the package -// where they are defined, the decoder will simply skip them. -// -// For this output type definition: -// -// type Exported struct { -// private string // this unexported field will be skipped -// Public string -// } -// -// Using this map as input: -// -// map[string]interface{}{ -// "private": "I will be ignored", -// "Public": "I made it through!", -// } -// -// The following struct will be decoded: -// -// type Exported struct { -// private: "" // field is left with an empty string (zero value) -// Public: "I made it through!" -// } -// -// # Other Configuration -// -// mapstructure is highly configurable. See the DecoderConfig struct -// for other features and options that are supported. -package mapstructure - -import ( - "encoding/json" - "fmt" - "reflect" - "sort" - "strconv" - "strings" - - "github.com/go-viper/mapstructure/v2/internal/errors" -) - -// DecodeHookFunc is the callback function that can be used for -// data transformations. See "DecodeHook" in the DecoderConfig -// struct. -// -// The type must be one of DecodeHookFuncType, DecodeHookFuncKind, or -// DecodeHookFuncValue. -// Values are a superset of Types (Values can return types), and Types are a -// superset of Kinds (Types can return Kinds) and are generally a richer thing -// to use, but Kinds are simpler if you only need those. -// -// The reason DecodeHookFunc is multi-typed is for backwards compatibility: -// we started with Kinds and then realized Types were the better solution, -// but have a promise to not break backwards compat so we now support -// both. -type DecodeHookFunc interface{} - -// DecodeHookFuncType is a DecodeHookFunc which has complete information about -// the source and target types. -type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) - -// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the -// source and target types. -type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) - -// DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target -// values. -type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) - -// DecoderConfig is the configuration that is used to create a new decoder -// and allows customization of various aspects of decoding. -type DecoderConfig struct { - // DecodeHook, if set, will be called before any decoding and any - // type conversion (if WeaklyTypedInput is on). This lets you modify - // the values before they're set down onto the resulting struct. The - // DecodeHook is called for every map and value in the input. This means - // that if a struct has embedded fields with squash tags the decode hook - // is called only once with all of the input data, not once for each - // embedded struct. - // - // If an error is returned, the entire decode will fail with that error. - DecodeHook DecodeHookFunc - - // If ErrorUnused is true, then it is an error for there to exist - // keys in the original map that were unused in the decoding process - // (extra keys). - ErrorUnused bool - - // If ErrorUnset is true, then it is an error for there to exist - // fields in the result that were not set in the decoding process - // (extra fields). This only applies to decoding to a struct. This - // will affect all nested structs as well. - ErrorUnset bool - - // ZeroFields, if set to true, will zero fields before writing them. - // For example, a map will be emptied before decoded values are put in - // it. If this is false, a map will be merged. - ZeroFields bool - - // If WeaklyTypedInput is true, the decoder will make the following - // "weak" conversions: - // - // - bools to string (true = "1", false = "0") - // - numbers to string (base 10) - // - bools to int/uint (true = 1, false = 0) - // - strings to int/uint (base implied by prefix) - // - int to bool (true if value != 0) - // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, - // FALSE, false, False. Anything else is an error) - // - empty array = empty map and vice versa - // - negative numbers to overflowed uint values (base 10) - // - slice of maps to a merged map - // - single values are converted to slices if required. Each - // element is weakly decoded. For example: "4" can become []int{4} - // if the target type is an int slice. - // - WeaklyTypedInput bool - - // Squash will squash embedded structs. A squash tag may also be - // added to an individual struct field using a tag. For example: - // - // type Parent struct { - // Child `mapstructure:",squash"` - // } - Squash bool - - // Metadata is the struct that will contain extra metadata about - // the decoding. If this is nil, then no metadata will be tracked. - Metadata *Metadata - - // Result is a pointer to the struct that will contain the decoded - // value. - Result interface{} - - // The tag name that mapstructure reads for field names. This - // defaults to "mapstructure" - TagName string - - // The option of the value in the tag that indicates a field should - // be squashed. This defaults to "squash". - SquashTagOption string - - // IgnoreUntaggedFields ignores all struct fields without explicit - // TagName, comparable to `mapstructure:"-"` as default behaviour. - IgnoreUntaggedFields bool - - // MatchName is the function used to match the map key to the struct - // field name or tag. Defaults to `strings.EqualFold`. This can be used - // to implement case-sensitive tag values, support snake casing, etc. - MatchName func(mapKey, fieldName string) bool - - // DecodeNil, if set to true, will cause the DecodeHook (if present) to run - // even if the input is nil. This can be used to provide default values. - DecodeNil bool -} - -// A Decoder takes a raw interface value and turns it into structured -// data, keeping track of rich error information along the way in case -// anything goes wrong. Unlike the basic top-level Decode method, you can -// more finely control how the Decoder behaves using the DecoderConfig -// structure. The top-level Decode method is just a convenience that sets -// up the most basic Decoder. -type Decoder struct { - config *DecoderConfig - cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error) -} - -// Metadata contains information about decoding a structure that -// is tedious or difficult to get otherwise. -type Metadata struct { - // Keys are the keys of the structure which were successfully decoded - Keys []string - - // Unused is a slice of keys that were found in the raw value but - // weren't decoded since there was no matching field in the result interface - Unused []string - - // Unset is a slice of field names that were found in the result interface - // but weren't set in the decoding process since there was no matching value - // in the input - Unset []string -} - -// Decode takes an input structure and uses reflection to translate it to -// the output structure. output must be a pointer to a map or struct. -func Decode(input interface{}, output interface{}) error { - config := &DecoderConfig{ - Metadata: nil, - Result: output, - } - - decoder, err := NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(input) -} - -// WeakDecode is the same as Decode but is shorthand to enable -// WeaklyTypedInput. See DecoderConfig for more info. -func WeakDecode(input, output interface{}) error { - config := &DecoderConfig{ - Metadata: nil, - Result: output, - WeaklyTypedInput: true, - } - - decoder, err := NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(input) -} - -// DecodeMetadata is the same as Decode, but is shorthand to -// enable metadata collection. See DecoderConfig for more info. -func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { - config := &DecoderConfig{ - Metadata: metadata, - Result: output, - } - - decoder, err := NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(input) -} - -// WeakDecodeMetadata is the same as Decode, but is shorthand to -// enable both WeaklyTypedInput and metadata collection. See -// DecoderConfig for more info. -func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { - config := &DecoderConfig{ - Metadata: metadata, - Result: output, - WeaklyTypedInput: true, - } - - decoder, err := NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(input) -} - -// NewDecoder returns a new decoder for the given configuration. Once -// a decoder has been returned, the same configuration must not be used -// again. -func NewDecoder(config *DecoderConfig) (*Decoder, error) { - val := reflect.ValueOf(config.Result) - if val.Kind() != reflect.Ptr { - return nil, errors.New("result must be a pointer") - } - - val = val.Elem() - if !val.CanAddr() { - return nil, errors.New("result must be addressable (a pointer)") - } - - if config.Metadata != nil { - if config.Metadata.Keys == nil { - config.Metadata.Keys = make([]string, 0) - } - - if config.Metadata.Unused == nil { - config.Metadata.Unused = make([]string, 0) - } - - if config.Metadata.Unset == nil { - config.Metadata.Unset = make([]string, 0) - } - } - - if config.TagName == "" { - config.TagName = "mapstructure" - } - - if config.SquashTagOption == "" { - config.SquashTagOption = "squash" - } - - if config.MatchName == nil { - config.MatchName = strings.EqualFold - } - - result := &Decoder{ - config: config, - } - if config.DecodeHook != nil { - result.cachedDecodeHook = cachedDecodeHook(config.DecodeHook) - } - - return result, nil -} - -// Decode decodes the given raw interface to the target pointer specified -// by the configuration. -func (d *Decoder) Decode(input interface{}) error { - err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) - - // Retain some of the original behavior when multiple errors ocurr - var joinedErr interface{ Unwrap() []error } - if errors.As(err, &joinedErr) { - return fmt.Errorf("decoding failed due to the following error(s):\n\n%w", err) - } - - return err -} - -// isNil returns true if the input is nil or a typed nil pointer. -func isNil(input interface{}) bool { - if input == nil { - return true - } - val := reflect.ValueOf(input) - return val.Kind() == reflect.Ptr && val.IsNil() -} - -// Decodes an unknown data type into a specific reflection value. -func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { - var ( - inputVal = reflect.ValueOf(input) - outputKind = getKind(outVal) - decodeNil = d.config.DecodeNil && d.cachedDecodeHook != nil - ) - if isNil(input) { - // Typed nils won't match the "input == nil" below, so reset input. - input = nil - } - if input == nil { - // If the data is nil, then we don't set anything, unless ZeroFields is set - // to true. - if d.config.ZeroFields { - outVal.Set(reflect.Zero(outVal.Type())) - - if d.config.Metadata != nil && name != "" { - d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) - } - } - if !decodeNil { - return nil - } - } - if !inputVal.IsValid() { - if !decodeNil { - // If the input value is invalid, then we just set the value - // to be the zero value. - outVal.Set(reflect.Zero(outVal.Type())) - if d.config.Metadata != nil && name != "" { - d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) - } - return nil - } - // Hooks need a valid inputVal, so reset it to zero value of outVal type. - switch outputKind { - case reflect.Struct, reflect.Map: - var mapVal map[string]interface{} - inputVal = reflect.ValueOf(mapVal) // create nil map pointer - case reflect.Slice, reflect.Array: - var sliceVal []interface{} - inputVal = reflect.ValueOf(sliceVal) // create nil slice pointer - default: - inputVal = reflect.Zero(outVal.Type()) - } - } - - if d.cachedDecodeHook != nil { - // We have a DecodeHook, so let's pre-process the input. - var err error - input, err = d.cachedDecodeHook(inputVal, outVal) - if err != nil { - return fmt.Errorf("error decoding '%s': %w", name, err) - } - } - if isNil(input) { - return nil - } - - var err error - addMetaKey := true - switch outputKind { - case reflect.Bool: - err = d.decodeBool(name, input, outVal) - case reflect.Interface: - err = d.decodeBasic(name, input, outVal) - case reflect.String: - err = d.decodeString(name, input, outVal) - case reflect.Int: - err = d.decodeInt(name, input, outVal) - case reflect.Uint: - err = d.decodeUint(name, input, outVal) - case reflect.Float32: - err = d.decodeFloat(name, input, outVal) - case reflect.Complex64: - err = d.decodeComplex(name, input, outVal) - case reflect.Struct: - err = d.decodeStruct(name, input, outVal) - case reflect.Map: - err = d.decodeMap(name, input, outVal) - case reflect.Ptr: - addMetaKey, err = d.decodePtr(name, input, outVal) - case reflect.Slice: - err = d.decodeSlice(name, input, outVal) - case reflect.Array: - err = d.decodeArray(name, input, outVal) - case reflect.Func: - err = d.decodeFunc(name, input, outVal) - default: - // If we reached this point then we weren't able to decode it - return fmt.Errorf("%s: unsupported type: %s", name, outputKind) - } - - // If we reached here, then we successfully decoded SOMETHING, so - // mark the key as used if we're tracking metainput. - if addMetaKey && d.config.Metadata != nil && name != "" { - d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) - } - - return err -} - -// This decodes a basic type (bool, int, string, etc.) and sets the -// value to "data" of that type. -func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { - if val.IsValid() && val.Elem().IsValid() { - elem := val.Elem() - - // If we can't address this element, then its not writable. Instead, - // we make a copy of the value (which is a pointer and therefore - // writable), decode into that, and replace the whole value. - copied := false - if !elem.CanAddr() { - copied = true - - // Make *T - copy := reflect.New(elem.Type()) - - // *T = elem - copy.Elem().Set(elem) - - // Set elem so we decode into it - elem = copy - } - - // Decode. If we have an error then return. We also return right - // away if we're not a copy because that means we decoded directly. - if err := d.decode(name, data, elem); err != nil || !copied { - return err - } - - // If we're a copy, we need to set te final result - val.Set(elem.Elem()) - return nil - } - - dataVal := reflect.ValueOf(data) - - // If the input data is a pointer, and the assigned type is the dereference - // of that exact pointer, then indirect it so that we can assign it. - // Example: *string to string - if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() { - dataVal = reflect.Indirect(dataVal) - } - - if !dataVal.IsValid() { - dataVal = reflect.Zero(val.Type()) - } - - dataValType := dataVal.Type() - if !dataValType.AssignableTo(val.Type()) { - return fmt.Errorf( - "'%s' expected type '%s', got '%s'", - name, val.Type(), dataValType) - } - - val.Set(dataVal) - return nil -} - -func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataKind := getKind(dataVal) - - converted := true - switch { - case dataKind == reflect.String: - val.SetString(dataVal.String()) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetString("1") - } else { - val.SetString("0") - } - case dataKind == reflect.Int && d.config.WeaklyTypedInput: - val.SetString(strconv.FormatInt(dataVal.Int(), 10)) - case dataKind == reflect.Uint && d.config.WeaklyTypedInput: - val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) - case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: - val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) - case dataKind == reflect.Slice && d.config.WeaklyTypedInput, - dataKind == reflect.Array && d.config.WeaklyTypedInput: - dataType := dataVal.Type() - elemKind := dataType.Elem().Kind() - switch elemKind { - case reflect.Uint8: - var uints []uint8 - if dataKind == reflect.Array { - uints = make([]uint8, dataVal.Len(), dataVal.Len()) - for i := range uints { - uints[i] = dataVal.Index(i).Interface().(uint8) - } - } else { - uints = dataVal.Interface().([]uint8) - } - val.SetString(string(uints)) - default: - converted = false - } - default: - converted = false - } - - if !converted { - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) - } - - return nil -} - -func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataKind := getKind(dataVal) - dataType := dataVal.Type() - - switch { - case dataKind == reflect.Int: - val.SetInt(dataVal.Int()) - case dataKind == reflect.Uint: - val.SetInt(int64(dataVal.Uint())) - case dataKind == reflect.Float32: - val.SetInt(int64(dataVal.Float())) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetInt(1) - } else { - val.SetInt(0) - } - case dataKind == reflect.String && d.config.WeaklyTypedInput: - str := dataVal.String() - if str == "" { - str = "0" - } - - i, err := strconv.ParseInt(str, 0, val.Type().Bits()) - if err == nil { - val.SetInt(i) - } else { - return fmt.Errorf("cannot parse '%s' as int: %s", name, err) - } - case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": - jn := data.(json.Number) - i, err := jn.Int64() - if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) - } - val.SetInt(i) - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) - } - - return nil -} - -func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataKind := getKind(dataVal) - dataType := dataVal.Type() - - switch { - case dataKind == reflect.Int: - i := dataVal.Int() - if i < 0 && !d.config.WeaklyTypedInput { - return fmt.Errorf("cannot parse '%s', %d overflows uint", - name, i) - } - val.SetUint(uint64(i)) - case dataKind == reflect.Uint: - val.SetUint(dataVal.Uint()) - case dataKind == reflect.Float32: - f := dataVal.Float() - if f < 0 && !d.config.WeaklyTypedInput { - return fmt.Errorf("cannot parse '%s', %f overflows uint", - name, f) - } - val.SetUint(uint64(f)) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetUint(1) - } else { - val.SetUint(0) - } - case dataKind == reflect.String && d.config.WeaklyTypedInput: - str := dataVal.String() - if str == "" { - str = "0" - } - - i, err := strconv.ParseUint(str, 0, val.Type().Bits()) - if err == nil { - val.SetUint(i) - } else { - return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) - } - case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": - jn := data.(json.Number) - i, err := strconv.ParseUint(string(jn), 0, 64) - if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) - } - val.SetUint(i) - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) - } - - return nil -} - -func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataKind := getKind(dataVal) - - switch { - case dataKind == reflect.Bool: - val.SetBool(dataVal.Bool()) - case dataKind == reflect.Int && d.config.WeaklyTypedInput: - val.SetBool(dataVal.Int() != 0) - case dataKind == reflect.Uint && d.config.WeaklyTypedInput: - val.SetBool(dataVal.Uint() != 0) - case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: - val.SetBool(dataVal.Float() != 0) - case dataKind == reflect.String && d.config.WeaklyTypedInput: - b, err := strconv.ParseBool(dataVal.String()) - if err == nil { - val.SetBool(b) - } else if dataVal.String() == "" { - val.SetBool(false) - } else { - return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) - } - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%#v', value: '%#v'", - name, val, dataVal, data) - } - - return nil -} - -func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataKind := getKind(dataVal) - dataType := dataVal.Type() - - switch { - case dataKind == reflect.Int: - val.SetFloat(float64(dataVal.Int())) - case dataKind == reflect.Uint: - val.SetFloat(float64(dataVal.Uint())) - case dataKind == reflect.Float32: - val.SetFloat(dataVal.Float()) - case dataKind == reflect.Bool && d.config.WeaklyTypedInput: - if dataVal.Bool() { - val.SetFloat(1) - } else { - val.SetFloat(0) - } - case dataKind == reflect.String && d.config.WeaklyTypedInput: - str := dataVal.String() - if str == "" { - str = "0" - } - - f, err := strconv.ParseFloat(str, val.Type().Bits()) - if err == nil { - val.SetFloat(f) - } else { - return fmt.Errorf("cannot parse '%s' as float: %s", name, err) - } - case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": - jn := data.(json.Number) - i, err := jn.Float64() - if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) - } - val.SetFloat(i) - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) - } - - return nil -} - -func (d *Decoder) decodeComplex(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataKind := getKind(dataVal) - - switch { - case dataKind == reflect.Complex64: - val.SetComplex(dataVal.Complex()) - default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) - } - - return nil -} - -func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { - valType := val.Type() - valKeyType := valType.Key() - valElemType := valType.Elem() - - // By default we overwrite keys in the current map - valMap := val - - // If the map is nil or we're purposely zeroing fields, make a new map - if valMap.IsNil() || d.config.ZeroFields { - // Make a new map to hold our result - mapType := reflect.MapOf(valKeyType, valElemType) - valMap = reflect.MakeMap(mapType) - } - - dataVal := reflect.ValueOf(data) - - // Resolve any levels of indirection - for dataVal.Kind() == reflect.Pointer { - dataVal = reflect.Indirect(dataVal) - } - - // Check input type and based on the input type jump to the proper func - switch dataVal.Kind() { - case reflect.Map: - return d.decodeMapFromMap(name, dataVal, val, valMap) - - case reflect.Struct: - return d.decodeMapFromStruct(name, dataVal, val, valMap) - - case reflect.Array, reflect.Slice: - if d.config.WeaklyTypedInput { - return d.decodeMapFromSlice(name, dataVal, val, valMap) - } - - fallthrough - - default: - return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) - } -} - -func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { - // Special case for BC reasons (covered by tests) - if dataVal.Len() == 0 { - val.Set(valMap) - return nil - } - - for i := 0; i < dataVal.Len(); i++ { - err := d.decode( - name+"["+strconv.Itoa(i)+"]", - dataVal.Index(i).Interface(), val) - if err != nil { - return err - } - } - - return nil -} - -func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { - valType := val.Type() - valKeyType := valType.Key() - valElemType := valType.Elem() - - // Accumulate errors - var errs []error - - // If the input data is empty, then we just match what the input data is. - if dataVal.Len() == 0 { - if dataVal.IsNil() { - if !val.IsNil() { - val.Set(dataVal) - } - } else { - // Set to empty allocated value - val.Set(valMap) - } - - return nil - } - - for _, k := range dataVal.MapKeys() { - fieldName := name + "[" + k.String() + "]" - - // First decode the key into the proper type - currentKey := reflect.Indirect(reflect.New(valKeyType)) - if err := d.decode(fieldName, k.Interface(), currentKey); err != nil { - errs = append(errs, err) - continue - } - - // Next decode the data into the proper type - v := dataVal.MapIndex(k).Interface() - currentVal := reflect.Indirect(reflect.New(valElemType)) - if err := d.decode(fieldName, v, currentVal); err != nil { - errs = append(errs, err) - continue - } - - valMap.SetMapIndex(currentKey, currentVal) - } - - // Set the built up map to the value - val.Set(valMap) - - return errors.Join(errs...) -} - -func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { - typ := dataVal.Type() - for i := 0; i < typ.NumField(); i++ { - // Get the StructField first since this is a cheap operation. If the - // field is unexported, then ignore it. - f := typ.Field(i) - if f.PkgPath != "" { - continue - } - - // Next get the actual value of this field and verify it is assignable - // to the map value. - v := dataVal.Field(i) - if !v.Type().AssignableTo(valMap.Type().Elem()) { - return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) - } - - tagValue := f.Tag.Get(d.config.TagName) - keyName := f.Name - - if tagValue == "" && d.config.IgnoreUntaggedFields { - continue - } - - // If Squash is set in the config, we squash the field down. - squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous - - v = dereferencePtrToStructIfNeeded(v, d.config.TagName) - - // Determine the name of the key in the map - if index := strings.Index(tagValue, ","); index != -1 { - if tagValue[:index] == "-" { - continue - } - // If "omitempty" is specified in the tag, it ignores empty values. - if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) { - continue - } - - // If "squash" is specified in the tag, we squash the field down. - squash = squash || strings.Contains(tagValue[index+1:], d.config.SquashTagOption) - if squash { - // When squashing, the embedded type can be a pointer to a struct. - if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { - v = v.Elem() - } - - // The final type must be a struct - if v.Kind() != reflect.Struct { - return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) - } - } else { - if strings.Index(tagValue[index+1:], "remain") != -1 { - if v.Kind() != reflect.Map { - return fmt.Errorf("error remain-tag field with invalid type: '%s'", v.Type()) - } - - ptr := v.MapRange() - for ptr.Next() { - valMap.SetMapIndex(ptr.Key(), ptr.Value()) - } - continue - } - } - if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" { - keyName = keyNameTagValue - } - } else if len(tagValue) > 0 { - if tagValue == "-" { - continue - } - keyName = tagValue - } - - switch v.Kind() { - // this is an embedded struct, so handle it differently - case reflect.Struct: - x := reflect.New(v.Type()) - x.Elem().Set(v) - - vType := valMap.Type() - vKeyType := vType.Key() - vElemType := vType.Elem() - mType := reflect.MapOf(vKeyType, vElemType) - vMap := reflect.MakeMap(mType) - - // Creating a pointer to a map so that other methods can completely - // overwrite the map if need be (looking at you decodeMapFromMap). The - // indirection allows the underlying map to be settable (CanSet() == true) - // where as reflect.MakeMap returns an unsettable map. - addrVal := reflect.New(vMap.Type()) - reflect.Indirect(addrVal).Set(vMap) - - err := d.decode(keyName, x.Interface(), reflect.Indirect(addrVal)) - if err != nil { - return err - } - - // the underlying map may have been completely overwritten so pull - // it indirectly out of the enclosing value. - vMap = reflect.Indirect(addrVal) - - if squash { - for _, k := range vMap.MapKeys() { - valMap.SetMapIndex(k, vMap.MapIndex(k)) - } - } else { - valMap.SetMapIndex(reflect.ValueOf(keyName), vMap) - } - - default: - valMap.SetMapIndex(reflect.ValueOf(keyName), v) - } - } - - if val.CanAddr() { - val.Set(valMap) - } - - return nil -} - -func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (bool, error) { - // If the input data is nil, then we want to just set the output - // pointer to be nil as well. - isNil := data == nil - if !isNil { - switch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() { - case reflect.Chan, - reflect.Func, - reflect.Interface, - reflect.Map, - reflect.Ptr, - reflect.Slice: - isNil = v.IsNil() - } - } - if isNil { - if !val.IsNil() && val.CanSet() { - nilValue := reflect.New(val.Type()).Elem() - val.Set(nilValue) - } - - return true, nil - } - - // Create an element of the concrete (non pointer) type and decode - // into that. Then set the value of the pointer to this type. - valType := val.Type() - valElemType := valType.Elem() - if val.CanSet() { - realVal := val - if realVal.IsNil() || d.config.ZeroFields { - realVal = reflect.New(valElemType) - } - - if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { - return false, err - } - - val.Set(realVal) - } else { - if err := d.decode(name, data, reflect.Indirect(val)); err != nil { - return false, err - } - } - return false, nil -} - -func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { - // Create an element of the concrete (non pointer) type and decode - // into that. Then set the value of the pointer to this type. - dataVal := reflect.Indirect(reflect.ValueOf(data)) - if val.Type() != dataVal.Type() { - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) - } - val.Set(dataVal) - return nil -} - -func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataValKind := dataVal.Kind() - valType := val.Type() - valElemType := valType.Elem() - sliceType := reflect.SliceOf(valElemType) - - // If we have a non array/slice type then we first attempt to convert. - if dataValKind != reflect.Array && dataValKind != reflect.Slice { - if d.config.WeaklyTypedInput { - switch { - // Slice and array we use the normal logic - case dataValKind == reflect.Slice, dataValKind == reflect.Array: - break - - // Empty maps turn into empty slices - case dataValKind == reflect.Map: - if dataVal.Len() == 0 { - val.Set(reflect.MakeSlice(sliceType, 0, 0)) - return nil - } - // Create slice of maps of other sizes - return d.decodeSlice(name, []interface{}{data}, val) - - case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: - return d.decodeSlice(name, []byte(dataVal.String()), val) - - // All other types we try to convert to the slice type - // and "lift" it into it. i.e. a string becomes a string slice. - default: - // Just re-try this function with data as a slice. - return d.decodeSlice(name, []interface{}{data}, val) - } - } - - return fmt.Errorf( - "'%s': source data must be an array or slice, got %s", name, dataValKind) - } - - // If the input value is nil, then don't allocate since empty != nil - if dataValKind != reflect.Array && dataVal.IsNil() { - return nil - } - - valSlice := val - if valSlice.IsNil() || d.config.ZeroFields { - // Make a new slice to hold our result, same size as the original data. - valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) - } else if valSlice.Len() > dataVal.Len() { - valSlice = valSlice.Slice(0, dataVal.Len()) - } - - // Accumulate any errors - var errs []error - - for i := 0; i < dataVal.Len(); i++ { - currentData := dataVal.Index(i).Interface() - for valSlice.Len() <= i { - valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) - } - currentField := valSlice.Index(i) - - fieldName := name + "[" + strconv.Itoa(i) + "]" - if err := d.decode(fieldName, currentData, currentField); err != nil { - errs = append(errs, err) - } - } - - // Finally, set the value to the slice we built up - val.Set(valSlice) - - return errors.Join(errs...) -} - -func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - dataValKind := dataVal.Kind() - valType := val.Type() - valElemType := valType.Elem() - arrayType := reflect.ArrayOf(valType.Len(), valElemType) - - valArray := val - - if isComparable(valArray) && valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.config.ZeroFields { - // Check input type - if dataValKind != reflect.Array && dataValKind != reflect.Slice { - if d.config.WeaklyTypedInput { - switch { - // Empty maps turn into empty arrays - case dataValKind == reflect.Map: - if dataVal.Len() == 0 { - val.Set(reflect.Zero(arrayType)) - return nil - } - - // All other types we try to convert to the array type - // and "lift" it into it. i.e. a string becomes a string array. - default: - // Just re-try this function with data as a slice. - return d.decodeArray(name, []interface{}{data}, val) - } - } - - return fmt.Errorf( - "'%s': source data must be an array or slice, got %s", name, dataValKind) - - } - if dataVal.Len() > arrayType.Len() { - return fmt.Errorf( - "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len()) - } - - // Make a new array to hold our result, same size as the original data. - valArray = reflect.New(arrayType).Elem() - } - - // Accumulate any errors - var errs []error - - for i := 0; i < dataVal.Len(); i++ { - currentData := dataVal.Index(i).Interface() - currentField := valArray.Index(i) - - fieldName := name + "[" + strconv.Itoa(i) + "]" - if err := d.decode(fieldName, currentData, currentField); err != nil { - errs = append(errs, err) - } - } - - // Finally, set the value to the array we built up - val.Set(valArray) - - return errors.Join(errs...) -} - -func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { - dataVal := reflect.Indirect(reflect.ValueOf(data)) - - // If the type of the value to write to and the data match directly, - // then we just set it directly instead of recursing into the structure. - if dataVal.Type() == val.Type() { - val.Set(dataVal) - return nil - } - - dataValKind := dataVal.Kind() - switch dataValKind { - case reflect.Map: - return d.decodeStructFromMap(name, dataVal, val) - - case reflect.Struct: - // Not the most efficient way to do this but we can optimize later if - // we want to. To convert from struct to struct we go to map first - // as an intermediary. - - // Make a new map to hold our result - mapType := reflect.TypeOf((map[string]interface{})(nil)) - mval := reflect.MakeMap(mapType) - - // Creating a pointer to a map so that other methods can completely - // overwrite the map if need be (looking at you decodeMapFromMap). The - // indirection allows the underlying map to be settable (CanSet() == true) - // where as reflect.MakeMap returns an unsettable map. - addrVal := reflect.New(mval.Type()) - - reflect.Indirect(addrVal).Set(mval) - if err := d.decodeMapFromStruct(name, dataVal, reflect.Indirect(addrVal), mval); err != nil { - return err - } - - result := d.decodeStructFromMap(name, reflect.Indirect(addrVal), val) - return result - - default: - return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) - } -} - -func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error { - dataValType := dataVal.Type() - if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { - return fmt.Errorf( - "'%s' needs a map with string keys, has '%s' keys", - name, dataValType.Key().Kind()) - } - - dataValKeys := make(map[reflect.Value]struct{}) - dataValKeysUnused := make(map[interface{}]struct{}) - for _, dataValKey := range dataVal.MapKeys() { - dataValKeys[dataValKey] = struct{}{} - dataValKeysUnused[dataValKey.Interface()] = struct{}{} - } - - targetValKeysUnused := make(map[interface{}]struct{}) - - var errs []error - - // This slice will keep track of all the structs we'll be decoding. - // There can be more than one struct if there are embedded structs - // that are squashed. - structs := make([]reflect.Value, 1, 5) - structs[0] = val - - // Compile the list of all the fields that we're going to be decoding - // from all the structs. - type field struct { - field reflect.StructField - val reflect.Value - } - - // remainField is set to a valid field set with the "remain" tag if - // we are keeping track of remaining values. - var remainField *field - - fields := []field{} - for len(structs) > 0 { - structVal := structs[0] - structs = structs[1:] - - structType := structVal.Type() - - for i := 0; i < structType.NumField(); i++ { - fieldType := structType.Field(i) - fieldVal := structVal.Field(i) - if fieldVal.Kind() == reflect.Ptr && fieldVal.Elem().Kind() == reflect.Struct { - // Handle embedded struct pointers as embedded structs. - fieldVal = fieldVal.Elem() - } - - // If "squash" is specified in the tag, we squash the field down. - squash := d.config.Squash && fieldVal.Kind() == reflect.Struct && fieldType.Anonymous - remain := false - - // We always parse the tags cause we're looking for other tags too - tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") - for _, tag := range tagParts[1:] { - if tag == d.config.SquashTagOption { - squash = true - break - } - - if tag == "remain" { - remain = true - break - } - } - - if squash { - switch fieldVal.Kind() { - case reflect.Struct: - structs = append(structs, fieldVal) - case reflect.Interface: - if !fieldVal.IsNil() { - structs = append(structs, fieldVal.Elem().Elem()) - } - default: - errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) - } - continue - } - - // Build our field - if remain { - remainField = &field{fieldType, fieldVal} - } else { - // Normal struct field, store it away - fields = append(fields, field{fieldType, fieldVal}) - } - } - } - - // for fieldType, field := range fields { - for _, f := range fields { - field, fieldValue := f.field, f.val - fieldName := field.Name - - tagValue := field.Tag.Get(d.config.TagName) - if tagValue == "" && d.config.IgnoreUntaggedFields { - continue - } - tagValue = strings.SplitN(tagValue, ",", 2)[0] - if tagValue != "" { - fieldName = tagValue - } - - rawMapKey := reflect.ValueOf(fieldName) - rawMapVal := dataVal.MapIndex(rawMapKey) - if !rawMapVal.IsValid() { - // Do a slower search by iterating over each key and - // doing case-insensitive search. - for dataValKey := range dataValKeys { - mK, ok := dataValKey.Interface().(string) - if !ok { - // Not a string key - continue - } - - if d.config.MatchName(mK, fieldName) { - rawMapKey = dataValKey - rawMapVal = dataVal.MapIndex(dataValKey) - break - } - } - - if !rawMapVal.IsValid() { - // There was no matching key in the map for the value in - // the struct. Remember it for potential errors and metadata. - targetValKeysUnused[fieldName] = struct{}{} - continue - } - } - - if !fieldValue.IsValid() { - // This should never happen - panic("field is not valid") - } - - // If we can't set the field, then it is unexported or something, - // and we just continue onwards. - if !fieldValue.CanSet() { - continue - } - - // Delete the key we're using from the unused map so we stop tracking - delete(dataValKeysUnused, rawMapKey.Interface()) - - // If the name is empty string, then we're at the root, and we - // don't dot-join the fields. - if name != "" { - fieldName = name + "." + fieldName - } - - if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil { - errs = append(errs, err) - } - } - - // If we have a "remain"-tagged field and we have unused keys then - // we put the unused keys directly into the remain field. - if remainField != nil && len(dataValKeysUnused) > 0 { - // Build a map of only the unused values - remain := map[interface{}]interface{}{} - for key := range dataValKeysUnused { - remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface() - } - - // Decode it as-if we were just decoding this map onto our map. - if err := d.decodeMap(name, remain, remainField.val); err != nil { - errs = append(errs, err) - } - - // Set the map to nil so we have none so that the next check will - // not error (ErrorUnused) - dataValKeysUnused = nil - } - - if d.config.ErrorUnused && len(dataValKeysUnused) > 0 { - keys := make([]string, 0, len(dataValKeysUnused)) - for rawKey := range dataValKeysUnused { - keys = append(keys, rawKey.(string)) - } - sort.Strings(keys) - - err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) - errs = append(errs, err) - } - - if d.config.ErrorUnset && len(targetValKeysUnused) > 0 { - keys := make([]string, 0, len(targetValKeysUnused)) - for rawKey := range targetValKeysUnused { - keys = append(keys, rawKey.(string)) - } - sort.Strings(keys) - - err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", ")) - errs = append(errs, err) - } - - if err := errors.Join(errs...); err != nil { - return err - } - - // Add the unused keys to the list of unused keys if we're tracking metadata - if d.config.Metadata != nil { - for rawKey := range dataValKeysUnused { - key := rawKey.(string) - if name != "" { - key = name + "." + key - } - - d.config.Metadata.Unused = append(d.config.Metadata.Unused, key) - } - for rawKey := range targetValKeysUnused { - key := rawKey.(string) - if name != "" { - key = name + "." + key - } - - d.config.Metadata.Unset = append(d.config.Metadata.Unset, key) - } - } - - return nil -} - -func isEmptyValue(v reflect.Value) bool { - switch getKind(v) { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - } - return false -} - -func getKind(val reflect.Value) reflect.Kind { - kind := val.Kind() - - switch { - case kind >= reflect.Int && kind <= reflect.Int64: - return reflect.Int - case kind >= reflect.Uint && kind <= reflect.Uint64: - return reflect.Uint - case kind >= reflect.Float32 && kind <= reflect.Float64: - return reflect.Float32 - case kind >= reflect.Complex64 && kind <= reflect.Complex128: - return reflect.Complex64 - default: - return kind - } -} - -func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, tagName string) bool { - for i := 0; i < typ.NumField(); i++ { - f := typ.Field(i) - if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields - return true - } - if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside - return true - } - } - return false -} - -func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value { - if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { - return v - } - deref := v.Elem() - derefT := deref.Type() - if isStructTypeConvertibleToMap(derefT, true, tagName) { - return deref - } - return v -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/reflect_go1_19.go b/vendor/github.com/go-viper/mapstructure/v2/reflect_go1_19.go deleted file mode 100644 index d0913ff..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/reflect_go1_19.go +++ /dev/null @@ -1,44 +0,0 @@ -//go:build !go1.20 - -package mapstructure - -import "reflect" - -func isComparable(v reflect.Value) bool { - k := v.Kind() - switch k { - case reflect.Invalid: - return false - - case reflect.Array: - switch v.Type().Elem().Kind() { - case reflect.Interface, reflect.Array, reflect.Struct: - for i := 0; i < v.Type().Len(); i++ { - // if !v.Index(i).Comparable() { - if !isComparable(v.Index(i)) { - return false - } - } - return true - } - return v.Type().Comparable() - - case reflect.Interface: - // return v.Elem().Comparable() - return isComparable(v.Elem()) - - case reflect.Struct: - for i := 0; i < v.NumField(); i++ { - return false - - // if !v.Field(i).Comparable() { - if !isComparable(v.Field(i)) { - return false - } - } - return true - - default: - return v.Type().Comparable() - } -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/reflect_go1_20.go b/vendor/github.com/go-viper/mapstructure/v2/reflect_go1_20.go deleted file mode 100644 index f8255a1..0000000 --- a/vendor/github.com/go-viper/mapstructure/v2/reflect_go1_20.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build go1.20 - -package mapstructure - -import "reflect" - -// TODO: remove once we drop support for Go <1.20 -func isComparable(v reflect.Value) bool { - return v.Comparable() -} diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md deleted file mode 100644 index 7ec5ac7..0000000 --- a/vendor/github.com/google/uuid/CHANGELOG.md +++ /dev/null @@ -1,41 +0,0 @@ -# Changelog - -## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) - - -### Features - -* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) - - -### Bug Fixes - -* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) -* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) - -## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) - - -### Features - -* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) - -## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) - - -### Features - -* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) - -### Fixes - -* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) - -## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) - - -### Bug Fixes - -* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) - -## Changelog diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md deleted file mode 100644 index a502fdc..0000000 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ /dev/null @@ -1,26 +0,0 @@ -# How to contribute - -We definitely welcome patches and contribution to this project! - -### Tips - -Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). - -Always try to include a test case! If it is not possible or not necessary, -please explain why in the pull request description. - -### Releasing - -Commits that would precipitate a SemVer change, as described in the Conventional -Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) -to create a release candidate pull request. Once submitted, `release-please` -will create a release. - -For tips on how to work with `release-please`, see its documentation. - -### Legal requirements - -In order to protect both you and ourselves, you will need to sign the -[Contributor License Agreement](https://cla.developers.google.com/clas). - -You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS deleted file mode 100644 index b4bb97f..0000000 --- a/vendor/github.com/google/uuid/CONTRIBUTORS +++ /dev/null @@ -1,9 +0,0 @@ -Paul Borman -bmatsuo -shawnps -theory -jboverfelt -dsymonds -cd1 -wallclockbuilder -dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE deleted file mode 100644 index 5dc6826..0000000 --- a/vendor/github.com/google/uuid/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009,2014 Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md deleted file mode 100644 index 3e9a618..0000000 --- a/vendor/github.com/google/uuid/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# uuid -The uuid package generates and inspects UUIDs based on -[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) -and DCE 1.1: Authentication and Security Services. - -This package is based on the github.com/pborman/uuid package (previously named -code.google.com/p/go-uuid). It differs from these earlier packages in that -a UUID is a 16 byte array rather than a byte slice. One loss due to this -change is the ability to represent an invalid UUID (vs a NIL UUID). - -###### Install -```sh -go get github.com/google/uuid -``` - -###### Documentation -[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) - -Full `go doc` style documentation for the package can be viewed online without -installing this package by using the GoDoc site here: -http://pkg.go.dev/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go deleted file mode 100644 index fa820b9..0000000 --- a/vendor/github.com/google/uuid/dce.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "fmt" - "os" -) - -// A Domain represents a Version 2 domain -type Domain byte - -// Domain constants for DCE Security (Version 2) UUIDs. -const ( - Person = Domain(0) - Group = Domain(1) - Org = Domain(2) -) - -// NewDCESecurity returns a DCE Security (Version 2) UUID. -// -// The domain should be one of Person, Group or Org. -// On a POSIX system the id should be the users UID for the Person -// domain and the users GID for the Group. The meaning of id for -// the domain Org or on non-POSIX systems is site defined. -// -// For a given domain/id pair the same token may be returned for up to -// 7 minutes and 10 seconds. -func NewDCESecurity(domain Domain, id uint32) (UUID, error) { - uuid, err := NewUUID() - if err == nil { - uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 - uuid[9] = byte(domain) - binary.BigEndian.PutUint32(uuid[0:], id) - } - return uuid, err -} - -// NewDCEPerson returns a DCE Security (Version 2) UUID in the person -// domain with the id returned by os.Getuid. -// -// NewDCESecurity(Person, uint32(os.Getuid())) -func NewDCEPerson() (UUID, error) { - return NewDCESecurity(Person, uint32(os.Getuid())) -} - -// NewDCEGroup returns a DCE Security (Version 2) UUID in the group -// domain with the id returned by os.Getgid. -// -// NewDCESecurity(Group, uint32(os.Getgid())) -func NewDCEGroup() (UUID, error) { - return NewDCESecurity(Group, uint32(os.Getgid())) -} - -// Domain returns the domain for a Version 2 UUID. Domains are only defined -// for Version 2 UUIDs. -func (uuid UUID) Domain() Domain { - return Domain(uuid[9]) -} - -// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 -// UUIDs. -func (uuid UUID) ID() uint32 { - return binary.BigEndian.Uint32(uuid[0:4]) -} - -func (d Domain) String() string { - switch d { - case Person: - return "Person" - case Group: - return "Group" - case Org: - return "Org" - } - return fmt.Sprintf("Domain%d", int(d)) -} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go deleted file mode 100644 index 5b8a4b9..0000000 --- a/vendor/github.com/google/uuid/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package uuid generates and inspects UUIDs. -// -// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security -// Services. -// -// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to -// maps or compared directly. -package uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go deleted file mode 100644 index dc60082..0000000 --- a/vendor/github.com/google/uuid/hash.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "crypto/md5" - "crypto/sha1" - "hash" -) - -// Well known namespace IDs and UUIDs -var ( - NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) - NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) - Nil UUID // empty UUID, all zeros - - // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. - Max = UUID{ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - } -) - -// NewHash returns a new UUID derived from the hash of space concatenated with -// data generated by h. The hash should be at least 16 byte in length. The -// first 16 bytes of the hash are used to form the UUID. The version of the -// UUID will be the lower 4 bits of version. NewHash is used to implement -// NewMD5 and NewSHA1. -func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { - h.Reset() - h.Write(space[:]) //nolint:errcheck - h.Write(data) //nolint:errcheck - s := h.Sum(nil) - var uuid UUID - copy(uuid[:], s) - uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) - uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant - return uuid -} - -// NewMD5 returns a new MD5 (Version 3) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(md5.New(), space, data, 3) -func NewMD5(space UUID, data []byte) UUID { - return NewHash(md5.New(), space, data, 3) -} - -// NewSHA1 returns a new SHA1 (Version 5) UUID based on the -// supplied name space and data. It is the same as calling: -// -// NewHash(sha1.New(), space, data, 5) -func NewSHA1(space UUID, data []byte) UUID { - return NewHash(sha1.New(), space, data, 5) -} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go deleted file mode 100644 index 14bd340..0000000 --- a/vendor/github.com/google/uuid/marshal.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "fmt" - -// MarshalText implements encoding.TextMarshaler. -func (uuid UUID) MarshalText() ([]byte, error) { - var js [36]byte - encodeHex(js[:], uuid) - return js[:], nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (uuid *UUID) UnmarshalText(data []byte) error { - id, err := ParseBytes(data) - if err != nil { - return err - } - *uuid = id - return nil -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (uuid UUID) MarshalBinary() ([]byte, error) { - return uuid[:], nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (uuid *UUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(uuid[:], data) - return nil -} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go deleted file mode 100644 index d651a2b..0000000 --- a/vendor/github.com/google/uuid/node.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "sync" -) - -var ( - nodeMu sync.Mutex - ifname string // name of interface being used - nodeID [6]byte // hardware for version 1 UUIDs - zeroID [6]byte // nodeID with only 0's -) - -// NodeInterface returns the name of the interface from which the NodeID was -// derived. The interface "user" is returned if the NodeID was set by -// SetNodeID. -func NodeInterface() string { - defer nodeMu.Unlock() - nodeMu.Lock() - return ifname -} - -// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. -// If name is "" then the first usable interface found will be used or a random -// Node ID will be generated. If a named interface cannot be found then false -// is returned. -// -// SetNodeInterface never fails when name is "". -func SetNodeInterface(name string) bool { - defer nodeMu.Unlock() - nodeMu.Lock() - return setNodeInterface(name) -} - -func setNodeInterface(name string) bool { - iname, addr := getHardwareInterface(name) // null implementation for js - if iname != "" && addr != nil { - ifname = iname - copy(nodeID[:], addr) - return true - } - - // We found no interfaces with a valid hardware address. If name - // does not specify a specific interface generate a random Node ID - // (section 4.1.6) - if name == "" { - ifname = "random" - randomBits(nodeID[:]) - return true - } - return false -} - -// NodeID returns a slice of a copy of the current Node ID, setting the Node ID -// if not already set. -func NodeID() []byte { - defer nodeMu.Unlock() - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - nid := nodeID - return nid[:] -} - -// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes -// of id are used. If id is less than 6 bytes then false is returned and the -// Node ID is not set. -func SetNodeID(id []byte) bool { - if len(id) < 6 { - return false - } - defer nodeMu.Unlock() - nodeMu.Lock() - copy(nodeID[:], id) - ifname = "user" - return true -} - -// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is -// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) NodeID() []byte { - var node [6]byte - copy(node[:], uuid[10:]) - return node[:] -} diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go deleted file mode 100644 index b2a0bc8..0000000 --- a/vendor/github.com/google/uuid/node_js.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build js - -package uuid - -// getHardwareInterface returns nil values for the JS version of the code. -// This removes the "net" dependency, because it is not used in the browser. -// Using the "net" library inflates the size of the transpiled JS code by 673k bytes. -func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go deleted file mode 100644 index 0cbbcdd..0000000 --- a/vendor/github.com/google/uuid/node_net.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !js - -package uuid - -import "net" - -var interfaces []net.Interface // cached list of interfaces - -// getHardwareInterface returns the name and hardware address of interface name. -// If name is "" then the name and hardware address of one of the system's -// interfaces is returned. If no interfaces are found (name does not exist or -// there are no interfaces) then "", nil is returned. -// -// Only addresses of at least 6 bytes are returned. -func getHardwareInterface(name string) (string, []byte) { - if interfaces == nil { - var err error - interfaces, err = net.Interfaces() - if err != nil { - return "", nil - } - } - for _, ifs := range interfaces { - if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { - return ifs.Name, ifs.HardwareAddr - } - } - return "", nil -} diff --git a/vendor/github.com/google/uuid/null.go b/vendor/github.com/google/uuid/null.go deleted file mode 100644 index d7fcbf2..0000000 --- a/vendor/github.com/google/uuid/null.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2021 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "database/sql/driver" - "encoding/json" - "fmt" -) - -var jsonNull = []byte("null") - -// NullUUID represents a UUID that may be null. -// NullUUID implements the SQL driver.Scanner interface so -// it can be used as a scan destination: -// -// var u uuid.NullUUID -// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) -// ... -// if u.Valid { -// // use u.UUID -// } else { -// // NULL value -// } -// -type NullUUID struct { - UUID UUID - Valid bool // Valid is true if UUID is not NULL -} - -// Scan implements the SQL driver.Scanner interface. -func (nu *NullUUID) Scan(value interface{}) error { - if value == nil { - nu.UUID, nu.Valid = Nil, false - return nil - } - - err := nu.UUID.Scan(value) - if err != nil { - nu.Valid = false - return err - } - - nu.Valid = true - return nil -} - -// Value implements the driver Valuer interface. -func (nu NullUUID) Value() (driver.Value, error) { - if !nu.Valid { - return nil, nil - } - // Delegate to UUID Value function - return nu.UUID.Value() -} - -// MarshalBinary implements encoding.BinaryMarshaler. -func (nu NullUUID) MarshalBinary() ([]byte, error) { - if nu.Valid { - return nu.UUID[:], nil - } - - return []byte(nil), nil -} - -// UnmarshalBinary implements encoding.BinaryUnmarshaler. -func (nu *NullUUID) UnmarshalBinary(data []byte) error { - if len(data) != 16 { - return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) - } - copy(nu.UUID[:], data) - nu.Valid = true - return nil -} - -// MarshalText implements encoding.TextMarshaler. -func (nu NullUUID) MarshalText() ([]byte, error) { - if nu.Valid { - return nu.UUID.MarshalText() - } - - return jsonNull, nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (nu *NullUUID) UnmarshalText(data []byte) error { - id, err := ParseBytes(data) - if err != nil { - nu.Valid = false - return err - } - nu.UUID = id - nu.Valid = true - return nil -} - -// MarshalJSON implements json.Marshaler. -func (nu NullUUID) MarshalJSON() ([]byte, error) { - if nu.Valid { - return json.Marshal(nu.UUID) - } - - return jsonNull, nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (nu *NullUUID) UnmarshalJSON(data []byte) error { - if bytes.Equal(data, jsonNull) { - *nu = NullUUID{} - return nil // valid null UUID - } - err := json.Unmarshal(data, &nu.UUID) - nu.Valid = err == nil - return err -} diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go deleted file mode 100644 index 2e02ec0..0000000 --- a/vendor/github.com/google/uuid/sql.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements sql.Scanner so UUIDs can be read from databases transparently. -// Currently, database types that map to string and []byte are supported. Please -// consult database-specific driver documentation for matching types. -func (uuid *UUID) Scan(src interface{}) error { - switch src := src.(type) { - case nil: - return nil - - case string: - // if an empty UUID comes from a table, we return a null UUID - if src == "" { - return nil - } - - // see Parse for required string format - u, err := Parse(src) - if err != nil { - return fmt.Errorf("Scan: %v", err) - } - - *uuid = u - - case []byte: - // if an empty UUID comes from a table, we return a null UUID - if len(src) == 0 { - return nil - } - - // assumes a simple slice of bytes if 16 bytes - // otherwise attempts to parse - if len(src) != 16 { - return uuid.Scan(string(src)) - } - copy((*uuid)[:], src) - - default: - return fmt.Errorf("Scan: unable to scan type %T into UUID", src) - } - - return nil -} - -// Value implements sql.Valuer so that UUIDs can be written to databases -// transparently. Currently, UUIDs map to strings. Please consult -// database-specific driver documentation for matching types. -func (uuid UUID) Value() (driver.Value, error) { - return uuid.String(), nil -} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go deleted file mode 100644 index c351129..0000000 --- a/vendor/github.com/google/uuid/time.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" - "sync" - "time" -) - -// A Time represents a time as the number of 100's of nanoseconds since 15 Oct -// 1582. -type Time int64 - -const ( - lillian = 2299160 // Julian day of 15 Oct 1582 - unix = 2440587 // Julian day of 1 Jan 1970 - epoch = unix - lillian // Days between epochs - g1582 = epoch * 86400 // seconds between epochs - g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs -) - -var ( - timeMu sync.Mutex - lasttime uint64 // last time we returned - clockSeq uint16 // clock sequence for this run - - timeNow = time.Now // for testing -) - -// UnixTime converts t the number of seconds and nanoseconds using the Unix -// epoch of 1 Jan 1970. -func (t Time) UnixTime() (sec, nsec int64) { - sec = int64(t - g1582ns100) - nsec = (sec % 10000000) * 100 - sec /= 10000000 - return sec, nsec -} - -// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and -// clock sequence as well as adjusting the clock sequence as needed. An error -// is returned if the current time cannot be determined. -func GetTime() (Time, uint16, error) { - defer timeMu.Unlock() - timeMu.Lock() - return getTime() -} - -func getTime() (Time, uint16, error) { - t := timeNow() - - // If we don't have a clock sequence already, set one. - if clockSeq == 0 { - setClockSequence(-1) - } - now := uint64(t.UnixNano()/100) + g1582ns100 - - // If time has gone backwards with this clock sequence then we - // increment the clock sequence - if now <= lasttime { - clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 - } - lasttime = now - return Time(now), clockSeq, nil -} - -// ClockSequence returns the current clock sequence, generating one if not -// already set. The clock sequence is only used for Version 1 UUIDs. -// -// The uuid package does not use global static storage for the clock sequence or -// the last time a UUID was generated. Unless SetClockSequence is used, a new -// random clock sequence is generated the first time a clock sequence is -// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) -func ClockSequence() int { - defer timeMu.Unlock() - timeMu.Lock() - return clockSequence() -} - -func clockSequence() int { - if clockSeq == 0 { - setClockSequence(-1) - } - return int(clockSeq & 0x3fff) -} - -// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to -// -1 causes a new sequence to be generated. -func SetClockSequence(seq int) { - defer timeMu.Unlock() - timeMu.Lock() - setClockSequence(seq) -} - -func setClockSequence(seq int) { - if seq == -1 { - var b [2]byte - randomBits(b[:]) // clock sequence - seq = int(b[0])<<8 | int(b[1]) - } - oldSeq := clockSeq - clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant - if oldSeq != clockSeq { - lasttime = 0 - } -} - -// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. -func (uuid UUID) Time() Time { - var t Time - switch uuid.Version() { - case 6: - time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 - t = Time(time) - case 7: - time := binary.BigEndian.Uint64(uuid[:8]) - t = Time((time>>16)*10000 + g1582ns100) - default: // forward compatible - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - t = Time(time) - } - return t -} - -// ClockSequence returns the clock sequence encoded in uuid. -// The clock sequence is only well defined for version 1 and 2 UUIDs. -func (uuid UUID) ClockSequence() int { - return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff -} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go deleted file mode 100644 index 5ea6c73..0000000 --- a/vendor/github.com/google/uuid/util.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "io" -) - -// randomBits completely fills slice b with random data. -func randomBits(b []byte) { - if _, err := io.ReadFull(rander, b); err != nil { - panic(err.Error()) // rand should never fail - } -} - -// xvalues returns the value of a byte as a hexadecimal digit or 255. -var xvalues = [256]byte{ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -} - -// xtob converts hex characters x1 and x2 into a byte. -func xtob(x1, x2 byte) (byte, bool) { - b1 := xvalues[x1] - b2 := xvalues[x2] - return (b1 << 4) | b2, b1 != 255 && b2 != 255 -} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go deleted file mode 100644 index 5232b48..0000000 --- a/vendor/github.com/google/uuid/uuid.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2018 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "errors" - "fmt" - "io" - "strings" - "sync" -) - -// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC -// 4122. -type UUID [16]byte - -// A Version represents a UUID's version. -type Version byte - -// A Variant represents a UUID's variant. -type Variant byte - -// Constants returned by Variant. -const ( - Invalid = Variant(iota) // Invalid UUID - RFC4122 // The variant specified in RFC4122 - Reserved // Reserved, NCS backward compatibility. - Microsoft // Reserved, Microsoft Corporation backward compatibility. - Future // Reserved for future definition. -) - -const randPoolSize = 16 * 16 - -var ( - rander = rand.Reader // random function - poolEnabled = false - poolMu sync.Mutex - poolPos = randPoolSize // protected with poolMu - pool [randPoolSize]byte // protected with poolMu -) - -type invalidLengthError struct{ len int } - -func (err invalidLengthError) Error() string { - return fmt.Sprintf("invalid UUID length: %d", err.len) -} - -// IsInvalidLengthError is matcher function for custom error invalidLengthError -func IsInvalidLengthError(err error) bool { - _, ok := err.(invalidLengthError) - return ok -} - -// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both -// the standard UUID forms defined in RFC 4122 -// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, -// Parse accepts non-standard strings such as the raw hex encoding -// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, -// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are -// examined in the latter case. Parse should not be used to validate strings as -// it parses non-standard encodings as indicated above. -func Parse(s string) (UUID, error) { - var uuid UUID - switch len(s) { - // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36: - - // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: - if !strings.EqualFold(s[:9], "urn:uuid:") { - return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) - } - s = s[9:] - - // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - case 36 + 2: - s = s[1:] - - // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - case 32: - var ok bool - for i := range uuid { - uuid[i], ok = xtob(s[i*2], s[i*2+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, invalidLengthError{len(s)} - } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34, - } { - v, ok := xtob(s[x], s[x+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - uuid[i] = v - } - return uuid, nil -} - -// ParseBytes is like Parse, except it parses a byte slice instead of a string. -func ParseBytes(b []byte) (UUID, error) { - var uuid UUID - switch len(b) { - case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { - return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) - } - b = b[9:] - case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - b = b[1:] - case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - var ok bool - for i := 0; i < 32; i += 2 { - uuid[i/2], ok = xtob(b[i], b[i+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - } - return uuid, nil - default: - return uuid, invalidLengthError{len(b)} - } - // s is now at least 36 bytes long - // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { - return uuid, errors.New("invalid UUID format") - } - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34, - } { - v, ok := xtob(b[x], b[x+1]) - if !ok { - return uuid, errors.New("invalid UUID format") - } - uuid[i] = v - } - return uuid, nil -} - -// MustParse is like Parse but panics if the string cannot be parsed. -// It simplifies safe initialization of global variables holding compiled UUIDs. -func MustParse(s string) UUID { - uuid, err := Parse(s) - if err != nil { - panic(`uuid: Parse(` + s + `): ` + err.Error()) - } - return uuid -} - -// FromBytes creates a new UUID from a byte slice. Returns an error if the slice -// does not have a length of 16. The bytes are copied from the slice. -func FromBytes(b []byte) (uuid UUID, err error) { - err = uuid.UnmarshalBinary(b) - return uuid, err -} - -// Must returns uuid if err is nil and panics otherwise. -func Must(uuid UUID, err error) UUID { - if err != nil { - panic(err) - } - return uuid -} - -// Validate returns an error if s is not a properly formatted UUID in one of the following formats: -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} -// It returns an error if the format is invalid, otherwise nil. -func Validate(s string) error { - switch len(s) { - // Standard UUID format - case 36: - - // UUID with "urn:uuid:" prefix - case 36 + 9: - if !strings.EqualFold(s[:9], "urn:uuid:") { - return fmt.Errorf("invalid urn prefix: %q", s[:9]) - } - s = s[9:] - - // UUID enclosed in braces - case 36 + 2: - if s[0] != '{' || s[len(s)-1] != '}' { - return fmt.Errorf("invalid bracketed UUID format") - } - s = s[1 : len(s)-1] - - // UUID without hyphens - case 32: - for i := 0; i < len(s); i += 2 { - _, ok := xtob(s[i], s[i+1]) - if !ok { - return errors.New("invalid UUID format") - } - } - - default: - return invalidLengthError{len(s)} - } - - // Check for standard UUID format - if len(s) == 36 { - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return errors.New("invalid UUID format") - } - for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { - if _, ok := xtob(s[x], s[x+1]); !ok { - return errors.New("invalid UUID format") - } - } - } - - return nil -} - -// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// , or "" if uuid is invalid. -func (uuid UUID) String() string { - var buf [36]byte - encodeHex(buf[:], uuid) - return string(buf[:]) -} - -// URN returns the RFC 2141 URN form of uuid, -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. -func (uuid UUID) URN() string { - var buf [36 + 9]byte - copy(buf[:], "urn:uuid:") - encodeHex(buf[9:], uuid) - return string(buf[:]) -} - -func encodeHex(dst []byte, uuid UUID) { - hex.Encode(dst, uuid[:4]) - dst[8] = '-' - hex.Encode(dst[9:13], uuid[4:6]) - dst[13] = '-' - hex.Encode(dst[14:18], uuid[6:8]) - dst[18] = '-' - hex.Encode(dst[19:23], uuid[8:10]) - dst[23] = '-' - hex.Encode(dst[24:], uuid[10:]) -} - -// Variant returns the variant encoded in uuid. -func (uuid UUID) Variant() Variant { - switch { - case (uuid[8] & 0xc0) == 0x80: - return RFC4122 - case (uuid[8] & 0xe0) == 0xc0: - return Microsoft - case (uuid[8] & 0xe0) == 0xe0: - return Future - default: - return Reserved - } -} - -// Version returns the version of uuid. -func (uuid UUID) Version() Version { - return Version(uuid[6] >> 4) -} - -func (v Version) String() string { - if v > 15 { - return fmt.Sprintf("BAD_VERSION_%d", v) - } - return fmt.Sprintf("VERSION_%d", v) -} - -func (v Variant) String() string { - switch v { - case RFC4122: - return "RFC4122" - case Reserved: - return "Reserved" - case Microsoft: - return "Microsoft" - case Future: - return "Future" - case Invalid: - return "Invalid" - } - return fmt.Sprintf("BadVariant%d", int(v)) -} - -// SetRand sets the random number generator to r, which implements io.Reader. -// If r.Read returns an error when the package requests random data then -// a panic will be issued. -// -// Calling SetRand with nil sets the random number generator to the default -// generator. -func SetRand(r io.Reader) { - if r == nil { - rander = rand.Reader - return - } - rander = r -} - -// EnableRandPool enables internal randomness pool used for Random -// (Version 4) UUID generation. The pool contains random bytes read from -// the random number generator on demand in batches. Enabling the pool -// may improve the UUID generation throughput significantly. -// -// Since the pool is stored on the Go heap, this feature may be a bad fit -// for security sensitive applications. -// -// Both EnableRandPool and DisableRandPool are not thread-safe and should -// only be called when there is no possibility that New or any other -// UUID Version 4 generation function will be called concurrently. -func EnableRandPool() { - poolEnabled = true -} - -// DisableRandPool disables the randomness pool if it was previously -// enabled with EnableRandPool. -// -// Both EnableRandPool and DisableRandPool are not thread-safe and should -// only be called when there is no possibility that New or any other -// UUID Version 4 generation function will be called concurrently. -func DisableRandPool() { - poolEnabled = false - defer poolMu.Unlock() - poolMu.Lock() - poolPos = randPoolSize -} - -// UUIDs is a slice of UUID types. -type UUIDs []UUID - -// Strings returns a string slice containing the string form of each UUID in uuids. -func (uuids UUIDs) Strings() []string { - var uuidStrs = make([]string, len(uuids)) - for i, uuid := range uuids { - uuidStrs[i] = uuid.String() - } - return uuidStrs -} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go deleted file mode 100644 index 4631096..0000000 --- a/vendor/github.com/google/uuid/version1.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/binary" -) - -// NewUUID returns a Version 1 UUID based on the current NodeID and clock -// sequence, and the current time. If the NodeID has not been set by SetNodeID -// or SetNodeInterface then it will be set automatically. If the NodeID cannot -// be set NewUUID returns nil. If clock sequence has not been set by -// SetClockSequence then it will be set automatically. If GetTime fails to -// return the current NewUUID returns nil and an error. -// -// In most cases, New should be used. -func NewUUID() (UUID, error) { - var uuid UUID - now, seq, err := GetTime() - if err != nil { - return uuid, err - } - - timeLow := uint32(now & 0xffffffff) - timeMid := uint16((now >> 32) & 0xffff) - timeHi := uint16((now >> 48) & 0x0fff) - timeHi |= 0x1000 // Version 1 - - binary.BigEndian.PutUint32(uuid[0:], timeLow) - binary.BigEndian.PutUint16(uuid[4:], timeMid) - binary.BigEndian.PutUint16(uuid[6:], timeHi) - binary.BigEndian.PutUint16(uuid[8:], seq) - - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - copy(uuid[10:], nodeID[:]) - nodeMu.Unlock() - - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go deleted file mode 100644 index 7697802..0000000 --- a/vendor/github.com/google/uuid/version4.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "io" - -// New creates a new random UUID or panics. New is equivalent to -// the expression -// -// uuid.Must(uuid.NewRandom()) -func New() UUID { - return Must(NewRandom()) -} - -// NewString creates a new random UUID and returns it as a string or panics. -// NewString is equivalent to the expression -// -// uuid.New().String() -func NewString() string { - return Must(NewRandom()).String() -} - -// NewRandom returns a Random (Version 4) UUID. -// -// The strength of the UUIDs is based on the strength of the crypto/rand -// package. -// -// Uses the randomness pool if it was enabled with EnableRandPool. -// -// A note about uniqueness derived from the UUID Wikipedia entry: -// -// Randomly generated UUIDs have 122 random bits. One's annual risk of being -// hit by a meteorite is estimated to be one chance in 17 billion, that -// means the probability is about 0.00000000006 (6 × 10−11), -// equivalent to the odds of creating a few tens of trillions of UUIDs in a -// year and having one duplicate. -func NewRandom() (UUID, error) { - if !poolEnabled { - return NewRandomFromReader(rander) - } - return newRandomFromPool() -} - -// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. -func NewRandomFromReader(r io.Reader) (UUID, error) { - var uuid UUID - _, err := io.ReadFull(r, uuid[:]) - if err != nil { - return Nil, err - } - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} - -func newRandomFromPool() (UUID, error) { - var uuid UUID - poolMu.Lock() - if poolPos == randPoolSize { - _, err := io.ReadFull(rander, pool[:]) - if err != nil { - poolMu.Unlock() - return Nil, err - } - poolPos = 0 - } - copy(uuid[:], pool[poolPos:(poolPos+16)]) - poolPos += 16 - poolMu.Unlock() - - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go deleted file mode 100644 index 339a959..0000000 --- a/vendor/github.com/google/uuid/version6.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2023 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import "encoding/binary" - -// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. -// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. -// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. -// -// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 -// -// NewV6 returns a Version 6 UUID based on the current NodeID and clock -// sequence, and the current time. If the NodeID has not been set by SetNodeID -// or SetNodeInterface then it will be set automatically. If the NodeID cannot -// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by -// SetClockSequence then it will be set automatically. If GetTime fails to -// return the current NewV6 returns Nil and an error. -func NewV6() (UUID, error) { - var uuid UUID - now, seq, err := GetTime() - if err != nil { - return uuid, err - } - - /* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | time_high | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | time_mid | time_low_and_version | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |clk_seq_hi_res | clk_seq_low | node (0-1) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | node (2-5) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - - binary.BigEndian.PutUint64(uuid[0:], uint64(now)) - binary.BigEndian.PutUint16(uuid[8:], seq) - - uuid[6] = 0x60 | (uuid[6] & 0x0F) - uuid[8] = 0x80 | (uuid[8] & 0x3F) - - nodeMu.Lock() - if nodeID == zeroID { - setNodeInterface("") - } - copy(uuid[10:], nodeID[:]) - nodeMu.Unlock() - - return uuid, nil -} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go deleted file mode 100644 index 3167b64..0000000 --- a/vendor/github.com/google/uuid/version7.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2023 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "io" -) - -// UUID version 7 features a time-ordered value field derived from the widely -// implemented and well known Unix Epoch timestamp source, -// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. -// As well as improved entropy characteristics over versions 1 or 6. -// -// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 -// -// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. -// -// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). -// Uses the randomness pool if it was enabled with EnableRandPool. -// On error, NewV7 returns Nil and an error -func NewV7() (UUID, error) { - uuid, err := NewRandom() - if err != nil { - return uuid, err - } - makeV7(uuid[:]) - return uuid, nil -} - -// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). -// it use NewRandomFromReader fill random bits. -// On error, NewV7FromReader returns Nil and an error. -func NewV7FromReader(r io.Reader) (UUID, error) { - uuid, err := NewRandomFromReader(r) - if err != nil { - return uuid, err - } - - makeV7(uuid[:]) - return uuid, nil -} - -// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) -// uuid[8] already has the right version number (Variant is 10) -// see function NewV7 and NewV7FromReader -func makeV7(uuid []byte) { - /* - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | unix_ts_ms | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | unix_ts_ms | ver | rand_a (12 bit seq) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |var| rand_b | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | rand_b | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - _ = uuid[15] // bounds check - - t, s := getV7Time() - - uuid[0] = byte(t >> 40) - uuid[1] = byte(t >> 32) - uuid[2] = byte(t >> 24) - uuid[3] = byte(t >> 16) - uuid[4] = byte(t >> 8) - uuid[5] = byte(t) - - uuid[6] = 0x70 | (0x0F & byte(s>>8)) - uuid[7] = byte(s) -} - -// lastV7time is the last time we returned stored as: -// -// 52 bits of time in milliseconds since epoch -// 12 bits of (fractional nanoseconds) >> 8 -var lastV7time int64 - -const nanoPerMilli = 1000000 - -// getV7Time returns the time in milliseconds and nanoseconds / 256. -// The returned (milli << 12 + seq) is guarenteed to be greater than -// (milli << 12 + seq) returned by any previous call to getV7Time. -func getV7Time() (milli, seq int64) { - timeMu.Lock() - defer timeMu.Unlock() - - nano := timeNow().UnixNano() - milli = nano / nanoPerMilli - // Sequence number is between 0 and 3906 (nanoPerMilli>>8) - seq = (nano - milli*nanoPerMilli) >> 8 - now := milli<<12 + seq - if now <= lastV7time { - now = lastV7time + 1 - milli = now >> 12 - seq = now & 0xfff - } - lastV7time = now - return milli, seq -} diff --git a/vendor/github.com/gorilla/websocket/.gitignore b/vendor/github.com/gorilla/websocket/.gitignore deleted file mode 100644 index cd3fcd1..0000000 --- a/vendor/github.com/gorilla/websocket/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe - -.idea/ -*.iml diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml deleted file mode 100644 index 1f73047..0000000 --- a/vendor/github.com/gorilla/websocket/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go -sudo: false - -matrix: - include: - - go: 1.4 - - go: 1.5.x - - go: 1.6.x - - go: 1.7.x - - go: 1.8.x - - go: 1.9.x - - go: 1.10.x - - go: tip - allow_failures: - - go: tip - -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) - - go vet $(go list ./... | grep -v /vendor/) - - go test -v -race ./... diff --git a/vendor/github.com/gorilla/websocket/AUTHORS b/vendor/github.com/gorilla/websocket/AUTHORS deleted file mode 100644 index 1931f40..0000000 --- a/vendor/github.com/gorilla/websocket/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -# This is the official list of Gorilla WebSocket authors for copyright -# purposes. -# -# Please keep the list sorted. - -Gary Burd -Google LLC (https://opensource.google.com/) -Joachim Bauch - diff --git a/vendor/github.com/gorilla/websocket/LICENSE b/vendor/github.com/gorilla/websocket/LICENSE deleted file mode 100644 index 9171c97..0000000 --- a/vendor/github.com/gorilla/websocket/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md deleted file mode 100644 index 20e391f..0000000 --- a/vendor/github.com/gorilla/websocket/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Gorilla WebSocket - -Gorilla WebSocket is a [Go](http://golang.org/) implementation of the -[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. - -[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket) -[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) - -### Documentation - -* [API Reference](http://godoc.org/github.com/gorilla/websocket) -* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) -* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) -* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) -* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) - -### Status - -The Gorilla WebSocket package provides a complete and tested implementation of -the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The -package API is stable. - -### Installation - - go get github.com/gorilla/websocket - -### Protocol Compliance - -The Gorilla WebSocket package passes the server tests in the [Autobahn Test -Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn -subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). - -### Gorilla WebSocket compared with other packages - - - - - - - - - - - - - - - - - - -
github.com/gorillagolang.org/x/net
RFC 6455 Features
Passes Autobahn Test SuiteYesNo
Receive fragmented messageYesNo, see note 1
Send close messageYesNo
Send pings and receive pongsYesNo
Get the type of a received data messageYesYes, see note 2
Other Features
Compression ExtensionsExperimentalNo
Read message using io.ReaderYesNo, see note 3
Write message using io.WriteCloserYesNo, see note 3
- -Notes: - -1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html). -2. The application can get the type of a received data message by implementing - a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal) - function. -3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. - Read returns when the input buffer is full or a frame boundary is - encountered. Each call to Write sends a single frame message. The Gorilla - io.Reader and io.WriteCloser operate on a single WebSocket message. - diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go deleted file mode 100644 index 41f8ed5..0000000 --- a/vendor/github.com/gorilla/websocket/client.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bytes" - "crypto/tls" - "errors" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "strings" - "time" -) - -// ErrBadHandshake is returned when the server response to opening handshake is -// invalid. -var ErrBadHandshake = errors.New("websocket: bad handshake") - -var errInvalidCompression = errors.New("websocket: invalid compression negotiation") - -// NewClient creates a new client connection using the given net connection. -// The URL u specifies the host and request URI. Use requestHeader to specify -// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies -// (Cookie). Use the response.Header to get the selected subprotocol -// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). -// -// If the WebSocket handshake fails, ErrBadHandshake is returned along with a -// non-nil *http.Response so that callers can handle redirects, authentication, -// etc. -// -// Deprecated: Use Dialer instead. -func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) { - d := Dialer{ - ReadBufferSize: readBufSize, - WriteBufferSize: writeBufSize, - NetDial: func(net, addr string) (net.Conn, error) { - return netConn, nil - }, - } - return d.Dial(u.String(), requestHeader) -} - -// A Dialer contains options for connecting to WebSocket server. -type Dialer struct { - // NetDial specifies the dial function for creating TCP connections. If - // NetDial is nil, net.Dial is used. - NetDial func(network, addr string) (net.Conn, error) - - // Proxy specifies a function to return a proxy for a given - // Request. If the function returns a non-nil error, the - // request is aborted with the provided error. - // If Proxy is nil or returns a nil *URL, no proxy is used. - Proxy func(*http.Request) (*url.URL, error) - - // TLSClientConfig specifies the TLS configuration to use with tls.Client. - // If nil, the default configuration is used. - TLSClientConfig *tls.Config - - // HandshakeTimeout specifies the duration for the handshake to complete. - HandshakeTimeout time.Duration - - // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer - // size is zero, then a useful default size is used. The I/O buffer sizes - // do not limit the size of the messages that can be sent or received. - ReadBufferSize, WriteBufferSize int - - // Subprotocols specifies the client's requested subprotocols. - Subprotocols []string - - // EnableCompression specifies if the client should attempt to negotiate - // per message compression (RFC 7692). Setting this value to true does not - // guarantee that compression will be supported. Currently only "no context - // takeover" modes are supported. - EnableCompression bool - - // Jar specifies the cookie jar. - // If Jar is nil, cookies are not sent in requests and ignored - // in responses. - Jar http.CookieJar -} - -var errMalformedURL = errors.New("malformed ws or wss URL") - -func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { - hostPort = u.Host - hostNoPort = u.Host - if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") { - hostNoPort = hostNoPort[:i] - } else { - switch u.Scheme { - case "wss": - hostPort += ":443" - case "https": - hostPort += ":443" - default: - hostPort += ":80" - } - } - return hostPort, hostNoPort -} - -// DefaultDialer is a dialer with all fields set to the default values. -var DefaultDialer = &Dialer{ - Proxy: http.ProxyFromEnvironment, - HandshakeTimeout: 45 * time.Second, -} - -// nilDialer is dialer to use when receiver is nil. -var nilDialer Dialer = *DefaultDialer - -// Dial creates a new client connection. Use requestHeader to specify the -// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie). -// Use the response.Header to get the selected subprotocol -// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). -// -// If the WebSocket handshake fails, ErrBadHandshake is returned along with a -// non-nil *http.Response so that callers can handle redirects, authentication, -// etcetera. The response body may not contain the entire response and does not -// need to be closed by the application. -func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { - - if d == nil { - d = &nilDialer - } - - challengeKey, err := generateChallengeKey() - if err != nil { - return nil, nil, err - } - - u, err := url.Parse(urlStr) - if err != nil { - return nil, nil, err - } - - switch u.Scheme { - case "ws": - u.Scheme = "http" - case "wss": - u.Scheme = "https" - default: - return nil, nil, errMalformedURL - } - - if u.User != nil { - // User name and password are not allowed in websocket URIs. - return nil, nil, errMalformedURL - } - - req := &http.Request{ - Method: "GET", - URL: u, - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - Header: make(http.Header), - Host: u.Host, - } - - // Set the cookies present in the cookie jar of the dialer - if d.Jar != nil { - for _, cookie := range d.Jar.Cookies(u) { - req.AddCookie(cookie) - } - } - - // Set the request headers using the capitalization for names and values in - // RFC examples. Although the capitalization shouldn't matter, there are - // servers that depend on it. The Header.Set method is not used because the - // method canonicalizes the header names. - req.Header["Upgrade"] = []string{"websocket"} - req.Header["Connection"] = []string{"Upgrade"} - req.Header["Sec-WebSocket-Key"] = []string{challengeKey} - req.Header["Sec-WebSocket-Version"] = []string{"13"} - if len(d.Subprotocols) > 0 { - req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")} - } - for k, vs := range requestHeader { - switch { - case k == "Host": - if len(vs) > 0 { - req.Host = vs[0] - } - case k == "Upgrade" || - k == "Connection" || - k == "Sec-Websocket-Key" || - k == "Sec-Websocket-Version" || - k == "Sec-Websocket-Extensions" || - (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0): - return nil, nil, errors.New("websocket: duplicate header not allowed: " + k) - case k == "Sec-Websocket-Protocol": - req.Header["Sec-WebSocket-Protocol"] = vs - default: - req.Header[k] = vs - } - } - - if d.EnableCompression { - req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"} - } - - var deadline time.Time - if d.HandshakeTimeout != 0 { - deadline = time.Now().Add(d.HandshakeTimeout) - } - - // Get network dial function. - netDial := d.NetDial - if netDial == nil { - netDialer := &net.Dialer{Deadline: deadline} - netDial = netDialer.Dial - } - - // If needed, wrap the dial function to set the connection deadline. - if !deadline.Equal(time.Time{}) { - forwardDial := netDial - netDial = func(network, addr string) (net.Conn, error) { - c, err := forwardDial(network, addr) - if err != nil { - return nil, err - } - err = c.SetDeadline(deadline) - if err != nil { - c.Close() - return nil, err - } - return c, nil - } - } - - // If needed, wrap the dial function to connect through a proxy. - if d.Proxy != nil { - proxyURL, err := d.Proxy(req) - if err != nil { - return nil, nil, err - } - if proxyURL != nil { - dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial)) - if err != nil { - return nil, nil, err - } - netDial = dialer.Dial - } - } - - hostPort, hostNoPort := hostPortNoPort(u) - netConn, err := netDial("tcp", hostPort) - if err != nil { - return nil, nil, err - } - - defer func() { - if netConn != nil { - netConn.Close() - } - }() - - if u.Scheme == "https" { - cfg := cloneTLSConfig(d.TLSClientConfig) - if cfg.ServerName == "" { - cfg.ServerName = hostNoPort - } - tlsConn := tls.Client(netConn, cfg) - netConn = tlsConn - if err := tlsConn.Handshake(); err != nil { - return nil, nil, err - } - if !cfg.InsecureSkipVerify { - if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { - return nil, nil, err - } - } - } - - conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize) - - if err := req.Write(netConn); err != nil { - return nil, nil, err - } - - resp, err := http.ReadResponse(conn.br, req) - if err != nil { - return nil, nil, err - } - - if d.Jar != nil { - if rc := resp.Cookies(); len(rc) > 0 { - d.Jar.SetCookies(u, rc) - } - } - - if resp.StatusCode != 101 || - !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || - !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || - resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) { - // Before closing the network connection on return from this - // function, slurp up some of the response to aid application - // debugging. - buf := make([]byte, 1024) - n, _ := io.ReadFull(resp.Body, buf) - resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) - return nil, resp, ErrBadHandshake - } - - for _, ext := range parseExtensions(resp.Header) { - if ext[""] != "permessage-deflate" { - continue - } - _, snct := ext["server_no_context_takeover"] - _, cnct := ext["client_no_context_takeover"] - if !snct || !cnct { - return nil, resp, errInvalidCompression - } - conn.newCompressionWriter = compressNoContextTakeover - conn.newDecompressionReader = decompressNoContextTakeover - break - } - - resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) - conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") - - netConn.SetDeadline(time.Time{}) - netConn = nil // to avoid close in defer. - return conn, resp, nil -} diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go deleted file mode 100644 index 4f0d943..0000000 --- a/vendor/github.com/gorilla/websocket/client_clone.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.8 - -package websocket - -import "crypto/tls" - -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return cfg.Clone() -} diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go deleted file mode 100644 index babb007..0000000 --- a/vendor/github.com/gorilla/websocket/client_clone_legacy.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.8 - -package websocket - -import "crypto/tls" - -// cloneTLSConfig clones all public fields except the fields -// SessionTicketsDisabled and SessionTicketKey. This avoids copying the -// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a -// config in active use. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - } -} diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go deleted file mode 100644 index 813ffb1..0000000 --- a/vendor/github.com/gorilla/websocket/compression.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "compress/flate" - "errors" - "io" - "strings" - "sync" -) - -const ( - minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6 - maxCompressionLevel = flate.BestCompression - defaultCompressionLevel = 1 -) - -var ( - flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool - flateReaderPool = sync.Pool{New: func() interface{} { - return flate.NewReader(nil) - }} -) - -func decompressNoContextTakeover(r io.Reader) io.ReadCloser { - const tail = - // Add four bytes as specified in RFC - "\x00\x00\xff\xff" + - // Add final block to squelch unexpected EOF error from flate reader. - "\x01\x00\x00\xff\xff" - - fr, _ := flateReaderPool.Get().(io.ReadCloser) - fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) - return &flateReadWrapper{fr} -} - -func isValidCompressionLevel(level int) bool { - return minCompressionLevel <= level && level <= maxCompressionLevel -} - -func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser { - p := &flateWriterPools[level-minCompressionLevel] - tw := &truncWriter{w: w} - fw, _ := p.Get().(*flate.Writer) - if fw == nil { - fw, _ = flate.NewWriter(tw, level) - } else { - fw.Reset(tw) - } - return &flateWriteWrapper{fw: fw, tw: tw, p: p} -} - -// truncWriter is an io.Writer that writes all but the last four bytes of the -// stream to another io.Writer. -type truncWriter struct { - w io.WriteCloser - n int - p [4]byte -} - -func (w *truncWriter) Write(p []byte) (int, error) { - n := 0 - - // fill buffer first for simplicity. - if w.n < len(w.p) { - n = copy(w.p[w.n:], p) - p = p[n:] - w.n += n - if len(p) == 0 { - return n, nil - } - } - - m := len(p) - if m > len(w.p) { - m = len(w.p) - } - - if nn, err := w.w.Write(w.p[:m]); err != nil { - return n + nn, err - } - - copy(w.p[:], w.p[m:]) - copy(w.p[len(w.p)-m:], p[len(p)-m:]) - nn, err := w.w.Write(p[:len(p)-m]) - return n + nn, err -} - -type flateWriteWrapper struct { - fw *flate.Writer - tw *truncWriter - p *sync.Pool -} - -func (w *flateWriteWrapper) Write(p []byte) (int, error) { - if w.fw == nil { - return 0, errWriteClosed - } - return w.fw.Write(p) -} - -func (w *flateWriteWrapper) Close() error { - if w.fw == nil { - return errWriteClosed - } - err1 := w.fw.Flush() - w.p.Put(w.fw) - w.fw = nil - if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { - return errors.New("websocket: internal error, unexpected bytes at end of flate stream") - } - err2 := w.tw.w.Close() - if err1 != nil { - return err1 - } - return err2 -} - -type flateReadWrapper struct { - fr io.ReadCloser -} - -func (r *flateReadWrapper) Read(p []byte) (int, error) { - if r.fr == nil { - return 0, io.ErrClosedPipe - } - n, err := r.fr.Read(p) - if err == io.EOF { - // Preemptively place the reader back in the pool. This helps with - // scenarios where the application does not call NextReader() soon after - // this final read. - r.Close() - } - return n, err -} - -func (r *flateReadWrapper) Close() error { - if r.fr == nil { - return io.ErrClosedPipe - } - err := r.fr.Close() - flateReaderPool.Put(r.fr) - r.fr = nil - return err -} diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go deleted file mode 100644 index 5f46bf4..0000000 --- a/vendor/github.com/gorilla/websocket/conn.go +++ /dev/null @@ -1,1157 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "encoding/binary" - "errors" - "io" - "io/ioutil" - "math/rand" - "net" - "strconv" - "sync" - "time" - "unicode/utf8" -) - -const ( - // Frame header byte 0 bits from Section 5.2 of RFC 6455 - finalBit = 1 << 7 - rsv1Bit = 1 << 6 - rsv2Bit = 1 << 5 - rsv3Bit = 1 << 4 - - // Frame header byte 1 bits from Section 5.2 of RFC 6455 - maskBit = 1 << 7 - - maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask - maxControlFramePayloadSize = 125 - - writeWait = time.Second - - defaultReadBufferSize = 4096 - defaultWriteBufferSize = 4096 - - continuationFrame = 0 - noFrame = -1 -) - -// Close codes defined in RFC 6455, section 11.7. -const ( - CloseNormalClosure = 1000 - CloseGoingAway = 1001 - CloseProtocolError = 1002 - CloseUnsupportedData = 1003 - CloseNoStatusReceived = 1005 - CloseAbnormalClosure = 1006 - CloseInvalidFramePayloadData = 1007 - ClosePolicyViolation = 1008 - CloseMessageTooBig = 1009 - CloseMandatoryExtension = 1010 - CloseInternalServerErr = 1011 - CloseServiceRestart = 1012 - CloseTryAgainLater = 1013 - CloseTLSHandshake = 1015 -) - -// The message types are defined in RFC 6455, section 11.8. -const ( - // TextMessage denotes a text data message. The text message payload is - // interpreted as UTF-8 encoded text data. - TextMessage = 1 - - // BinaryMessage denotes a binary data message. - BinaryMessage = 2 - - // CloseMessage denotes a close control message. The optional message - // payload contains a numeric code and text. Use the FormatCloseMessage - // function to format a close message payload. - CloseMessage = 8 - - // PingMessage denotes a ping control message. The optional message payload - // is UTF-8 encoded text. - PingMessage = 9 - - // PongMessage denotes a pong control message. The optional message payload - // is UTF-8 encoded text. - PongMessage = 10 -) - -// ErrCloseSent is returned when the application writes a message to the -// connection after sending a close message. -var ErrCloseSent = errors.New("websocket: close sent") - -// ErrReadLimit is returned when reading a message that is larger than the -// read limit set for the connection. -var ErrReadLimit = errors.New("websocket: read limit exceeded") - -// netError satisfies the net Error interface. -type netError struct { - msg string - temporary bool - timeout bool -} - -func (e *netError) Error() string { return e.msg } -func (e *netError) Temporary() bool { return e.temporary } -func (e *netError) Timeout() bool { return e.timeout } - -// CloseError represents a close message. -type CloseError struct { - // Code is defined in RFC 6455, section 11.7. - Code int - - // Text is the optional text payload. - Text string -} - -func (e *CloseError) Error() string { - s := []byte("websocket: close ") - s = strconv.AppendInt(s, int64(e.Code), 10) - switch e.Code { - case CloseNormalClosure: - s = append(s, " (normal)"...) - case CloseGoingAway: - s = append(s, " (going away)"...) - case CloseProtocolError: - s = append(s, " (protocol error)"...) - case CloseUnsupportedData: - s = append(s, " (unsupported data)"...) - case CloseNoStatusReceived: - s = append(s, " (no status)"...) - case CloseAbnormalClosure: - s = append(s, " (abnormal closure)"...) - case CloseInvalidFramePayloadData: - s = append(s, " (invalid payload data)"...) - case ClosePolicyViolation: - s = append(s, " (policy violation)"...) - case CloseMessageTooBig: - s = append(s, " (message too big)"...) - case CloseMandatoryExtension: - s = append(s, " (mandatory extension missing)"...) - case CloseInternalServerErr: - s = append(s, " (internal server error)"...) - case CloseTLSHandshake: - s = append(s, " (TLS handshake error)"...) - } - if e.Text != "" { - s = append(s, ": "...) - s = append(s, e.Text...) - } - return string(s) -} - -// IsCloseError returns boolean indicating whether the error is a *CloseError -// with one of the specified codes. -func IsCloseError(err error, codes ...int) bool { - if e, ok := err.(*CloseError); ok { - for _, code := range codes { - if e.Code == code { - return true - } - } - } - return false -} - -// IsUnexpectedCloseError returns boolean indicating whether the error is a -// *CloseError with a code not in the list of expected codes. -func IsUnexpectedCloseError(err error, expectedCodes ...int) bool { - if e, ok := err.(*CloseError); ok { - for _, code := range expectedCodes { - if e.Code == code { - return false - } - } - return true - } - return false -} - -var ( - errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true} - errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()} - errBadWriteOpCode = errors.New("websocket: bad write message type") - errWriteClosed = errors.New("websocket: write closed") - errInvalidControlFrame = errors.New("websocket: invalid control frame") -) - -func newMaskKey() [4]byte { - n := rand.Uint32() - return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} -} - -func hideTempErr(err error) error { - if e, ok := err.(net.Error); ok && e.Temporary() { - err = &netError{msg: e.Error(), timeout: e.Timeout()} - } - return err -} - -func isControl(frameType int) bool { - return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage -} - -func isData(frameType int) bool { - return frameType == TextMessage || frameType == BinaryMessage -} - -var validReceivedCloseCodes = map[int]bool{ - // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number - - CloseNormalClosure: true, - CloseGoingAway: true, - CloseProtocolError: true, - CloseUnsupportedData: true, - CloseNoStatusReceived: false, - CloseAbnormalClosure: false, - CloseInvalidFramePayloadData: true, - ClosePolicyViolation: true, - CloseMessageTooBig: true, - CloseMandatoryExtension: true, - CloseInternalServerErr: true, - CloseServiceRestart: true, - CloseTryAgainLater: true, - CloseTLSHandshake: false, -} - -func isValidReceivedCloseCode(code int) bool { - return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999) -} - -// The Conn type represents a WebSocket connection. -type Conn struct { - conn net.Conn - isServer bool - subprotocol string - - // Write fields - mu chan bool // used as mutex to protect write to conn - writeBuf []byte // frame is constructed in this buffer. - writeDeadline time.Time - writer io.WriteCloser // the current writer returned to the application - isWriting bool // for best-effort concurrent write detection - - writeErrMu sync.Mutex - writeErr error - - enableWriteCompression bool - compressionLevel int - newCompressionWriter func(io.WriteCloser, int) io.WriteCloser - - // Read fields - reader io.ReadCloser // the current reader returned to the application - readErr error - br *bufio.Reader - readRemaining int64 // bytes remaining in current frame. - readFinal bool // true the current message has more frames. - readLength int64 // Message size. - readLimit int64 // Maximum message size. - readMaskPos int - readMaskKey [4]byte - handlePong func(string) error - handlePing func(string) error - handleClose func(int, string) error - readErrCount int - messageReader *messageReader // the current low-level reader - - readDecompress bool // whether last read frame had RSV1 set - newDecompressionReader func(io.Reader) io.ReadCloser -} - -func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn { - return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil) -} - -type writeHook struct { - p []byte -} - -func (wh *writeHook) Write(p []byte) (int, error) { - wh.p = p - return len(p), nil -} - -func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn { - mu := make(chan bool, 1) - mu <- true - - var br *bufio.Reader - if readBufferSize == 0 && brw != nil && brw.Reader != nil { - // Reuse the supplied bufio.Reader if the buffer has a useful size. - // This code assumes that peek on a reader returns - // bufio.Reader.buf[:0]. - brw.Reader.Reset(conn) - if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 { - br = brw.Reader - } - } - if br == nil { - if readBufferSize == 0 { - readBufferSize = defaultReadBufferSize - } - if readBufferSize < maxControlFramePayloadSize { - readBufferSize = maxControlFramePayloadSize - } - br = bufio.NewReaderSize(conn, readBufferSize) - } - - var writeBuf []byte - if writeBufferSize == 0 && brw != nil && brw.Writer != nil { - // Use the bufio.Writer's buffer if the buffer has a useful size. This - // code assumes that bufio.Writer.buf[:1] is passed to the - // bufio.Writer's underlying writer. - var wh writeHook - brw.Writer.Reset(&wh) - brw.Writer.WriteByte(0) - brw.Flush() - if cap(wh.p) >= maxFrameHeaderSize+256 { - writeBuf = wh.p[:cap(wh.p)] - } - } - - if writeBuf == nil { - if writeBufferSize == 0 { - writeBufferSize = defaultWriteBufferSize - } - writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize) - } - - c := &Conn{ - isServer: isServer, - br: br, - conn: conn, - mu: mu, - readFinal: true, - writeBuf: writeBuf, - enableWriteCompression: true, - compressionLevel: defaultCompressionLevel, - } - c.SetCloseHandler(nil) - c.SetPingHandler(nil) - c.SetPongHandler(nil) - return c -} - -// Subprotocol returns the negotiated protocol for the connection. -func (c *Conn) Subprotocol() string { - return c.subprotocol -} - -// Close closes the underlying network connection without sending or waiting -// for a close message. -func (c *Conn) Close() error { - return c.conn.Close() -} - -// LocalAddr returns the local network address. -func (c *Conn) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -// RemoteAddr returns the remote network address. -func (c *Conn) RemoteAddr() net.Addr { - return c.conn.RemoteAddr() -} - -// Write methods - -func (c *Conn) writeFatal(err error) error { - err = hideTempErr(err) - c.writeErrMu.Lock() - if c.writeErr == nil { - c.writeErr = err - } - c.writeErrMu.Unlock() - return err -} - -func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error { - <-c.mu - defer func() { c.mu <- true }() - - c.writeErrMu.Lock() - err := c.writeErr - c.writeErrMu.Unlock() - if err != nil { - return err - } - - c.conn.SetWriteDeadline(deadline) - if len(buf1) == 0 { - _, err = c.conn.Write(buf0) - } else { - err = c.writeBufs(buf0, buf1) - } - if err != nil { - return c.writeFatal(err) - } - if frameType == CloseMessage { - c.writeFatal(ErrCloseSent) - } - return nil -} - -// WriteControl writes a control message with the given deadline. The allowed -// message types are CloseMessage, PingMessage and PongMessage. -func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error { - if !isControl(messageType) { - return errBadWriteOpCode - } - if len(data) > maxControlFramePayloadSize { - return errInvalidControlFrame - } - - b0 := byte(messageType) | finalBit - b1 := byte(len(data)) - if !c.isServer { - b1 |= maskBit - } - - buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize) - buf = append(buf, b0, b1) - - if c.isServer { - buf = append(buf, data...) - } else { - key := newMaskKey() - buf = append(buf, key[:]...) - buf = append(buf, data...) - maskBytes(key, 0, buf[6:]) - } - - d := time.Hour * 1000 - if !deadline.IsZero() { - d = deadline.Sub(time.Now()) - if d < 0 { - return errWriteTimeout - } - } - - timer := time.NewTimer(d) - select { - case <-c.mu: - timer.Stop() - case <-timer.C: - return errWriteTimeout - } - defer func() { c.mu <- true }() - - c.writeErrMu.Lock() - err := c.writeErr - c.writeErrMu.Unlock() - if err != nil { - return err - } - - c.conn.SetWriteDeadline(deadline) - _, err = c.conn.Write(buf) - if err != nil { - return c.writeFatal(err) - } - if messageType == CloseMessage { - c.writeFatal(ErrCloseSent) - } - return err -} - -func (c *Conn) prepWrite(messageType int) error { - // Close previous writer if not already closed by the application. It's - // probably better to return an error in this situation, but we cannot - // change this without breaking existing applications. - if c.writer != nil { - c.writer.Close() - c.writer = nil - } - - if !isControl(messageType) && !isData(messageType) { - return errBadWriteOpCode - } - - c.writeErrMu.Lock() - err := c.writeErr - c.writeErrMu.Unlock() - return err -} - -// NextWriter returns a writer for the next message to send. The writer's Close -// method flushes the complete message to the network. -// -// There can be at most one open writer on a connection. NextWriter closes the -// previous writer if the application has not already done so. -// -// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and -// PongMessage) are supported. -func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { - if err := c.prepWrite(messageType); err != nil { - return nil, err - } - - mw := &messageWriter{ - c: c, - frameType: messageType, - pos: maxFrameHeaderSize, - } - c.writer = mw - if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { - w := c.newCompressionWriter(c.writer, c.compressionLevel) - mw.compress = true - c.writer = w - } - return c.writer, nil -} - -type messageWriter struct { - c *Conn - compress bool // whether next call to flushFrame should set RSV1 - pos int // end of data in writeBuf. - frameType int // type of the current frame. - err error -} - -func (w *messageWriter) fatal(err error) error { - if w.err != nil { - w.err = err - w.c.writer = nil - } - return err -} - -// flushFrame writes buffered data and extra as a frame to the network. The -// final argument indicates that this is the last frame in the message. -func (w *messageWriter) flushFrame(final bool, extra []byte) error { - c := w.c - length := w.pos - maxFrameHeaderSize + len(extra) - - // Check for invalid control frames. - if isControl(w.frameType) && - (!final || length > maxControlFramePayloadSize) { - return w.fatal(errInvalidControlFrame) - } - - b0 := byte(w.frameType) - if final { - b0 |= finalBit - } - if w.compress { - b0 |= rsv1Bit - } - w.compress = false - - b1 := byte(0) - if !c.isServer { - b1 |= maskBit - } - - // Assume that the frame starts at beginning of c.writeBuf. - framePos := 0 - if c.isServer { - // Adjust up if mask not included in the header. - framePos = 4 - } - - switch { - case length >= 65536: - c.writeBuf[framePos] = b0 - c.writeBuf[framePos+1] = b1 | 127 - binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length)) - case length > 125: - framePos += 6 - c.writeBuf[framePos] = b0 - c.writeBuf[framePos+1] = b1 | 126 - binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length)) - default: - framePos += 8 - c.writeBuf[framePos] = b0 - c.writeBuf[framePos+1] = b1 | byte(length) - } - - if !c.isServer { - key := newMaskKey() - copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) - maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos]) - if len(extra) > 0 { - return c.writeFatal(errors.New("websocket: internal error, extra used in client mode")) - } - } - - // Write the buffers to the connection with best-effort detection of - // concurrent writes. See the concurrency section in the package - // documentation for more info. - - if c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = true - - err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra) - - if !c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = false - - if err != nil { - return w.fatal(err) - } - - if final { - c.writer = nil - return nil - } - - // Setup for next frame. - w.pos = maxFrameHeaderSize - w.frameType = continuationFrame - return nil -} - -func (w *messageWriter) ncopy(max int) (int, error) { - n := len(w.c.writeBuf) - w.pos - if n <= 0 { - if err := w.flushFrame(false, nil); err != nil { - return 0, err - } - n = len(w.c.writeBuf) - w.pos - } - if n > max { - n = max - } - return n, nil -} - -func (w *messageWriter) Write(p []byte) (int, error) { - if w.err != nil { - return 0, w.err - } - - if len(p) > 2*len(w.c.writeBuf) && w.c.isServer { - // Don't buffer large messages. - err := w.flushFrame(false, p) - if err != nil { - return 0, err - } - return len(p), nil - } - - nn := len(p) - for len(p) > 0 { - n, err := w.ncopy(len(p)) - if err != nil { - return 0, err - } - copy(w.c.writeBuf[w.pos:], p[:n]) - w.pos += n - p = p[n:] - } - return nn, nil -} - -func (w *messageWriter) WriteString(p string) (int, error) { - if w.err != nil { - return 0, w.err - } - - nn := len(p) - for len(p) > 0 { - n, err := w.ncopy(len(p)) - if err != nil { - return 0, err - } - copy(w.c.writeBuf[w.pos:], p[:n]) - w.pos += n - p = p[n:] - } - return nn, nil -} - -func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) { - if w.err != nil { - return 0, w.err - } - for { - if w.pos == len(w.c.writeBuf) { - err = w.flushFrame(false, nil) - if err != nil { - break - } - } - var n int - n, err = r.Read(w.c.writeBuf[w.pos:]) - w.pos += n - nn += int64(n) - if err != nil { - if err == io.EOF { - err = nil - } - break - } - } - return nn, err -} - -func (w *messageWriter) Close() error { - if w.err != nil { - return w.err - } - if err := w.flushFrame(true, nil); err != nil { - return err - } - w.err = errWriteClosed - return nil -} - -// WritePreparedMessage writes prepared message into connection. -func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error { - frameType, frameData, err := pm.frame(prepareKey{ - isServer: c.isServer, - compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType), - compressionLevel: c.compressionLevel, - }) - if err != nil { - return err - } - if c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = true - err = c.write(frameType, c.writeDeadline, frameData, nil) - if !c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = false - return err -} - -// WriteMessage is a helper method for getting a writer using NextWriter, -// writing the message and closing the writer. -func (c *Conn) WriteMessage(messageType int, data []byte) error { - - if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { - // Fast path with no allocations and single frame. - - if err := c.prepWrite(messageType); err != nil { - return err - } - mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize} - n := copy(c.writeBuf[mw.pos:], data) - mw.pos += n - data = data[n:] - return mw.flushFrame(true, data) - } - - w, err := c.NextWriter(messageType) - if err != nil { - return err - } - if _, err = w.Write(data); err != nil { - return err - } - return w.Close() -} - -// SetWriteDeadline sets the write deadline on the underlying network -// connection. After a write has timed out, the websocket state is corrupt and -// all future writes will return an error. A zero value for t means writes will -// not time out. -func (c *Conn) SetWriteDeadline(t time.Time) error { - c.writeDeadline = t - return nil -} - -// Read methods - -func (c *Conn) advanceFrame() (int, error) { - // 1. Skip remainder of previous frame. - - if c.readRemaining > 0 { - if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil { - return noFrame, err - } - } - - // 2. Read and parse first two bytes of frame header. - - p, err := c.read(2) - if err != nil { - return noFrame, err - } - - final := p[0]&finalBit != 0 - frameType := int(p[0] & 0xf) - mask := p[1]&maskBit != 0 - c.readRemaining = int64(p[1] & 0x7f) - - c.readDecompress = false - if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 { - c.readDecompress = true - p[0] &^= rsv1Bit - } - - if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 { - return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16)) - } - - switch frameType { - case CloseMessage, PingMessage, PongMessage: - if c.readRemaining > maxControlFramePayloadSize { - return noFrame, c.handleProtocolError("control frame length > 125") - } - if !final { - return noFrame, c.handleProtocolError("control frame not final") - } - case TextMessage, BinaryMessage: - if !c.readFinal { - return noFrame, c.handleProtocolError("message start before final message frame") - } - c.readFinal = final - case continuationFrame: - if c.readFinal { - return noFrame, c.handleProtocolError("continuation after final message frame") - } - c.readFinal = final - default: - return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType)) - } - - // 3. Read and parse frame length. - - switch c.readRemaining { - case 126: - p, err := c.read(2) - if err != nil { - return noFrame, err - } - c.readRemaining = int64(binary.BigEndian.Uint16(p)) - case 127: - p, err := c.read(8) - if err != nil { - return noFrame, err - } - c.readRemaining = int64(binary.BigEndian.Uint64(p)) - } - - // 4. Handle frame masking. - - if mask != c.isServer { - return noFrame, c.handleProtocolError("incorrect mask flag") - } - - if mask { - c.readMaskPos = 0 - p, err := c.read(len(c.readMaskKey)) - if err != nil { - return noFrame, err - } - copy(c.readMaskKey[:], p) - } - - // 5. For text and binary messages, enforce read limit and return. - - if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage { - - c.readLength += c.readRemaining - if c.readLimit > 0 && c.readLength > c.readLimit { - c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) - return noFrame, ErrReadLimit - } - - return frameType, nil - } - - // 6. Read control frame payload. - - var payload []byte - if c.readRemaining > 0 { - payload, err = c.read(int(c.readRemaining)) - c.readRemaining = 0 - if err != nil { - return noFrame, err - } - if c.isServer { - maskBytes(c.readMaskKey, 0, payload) - } - } - - // 7. Process control frame payload. - - switch frameType { - case PongMessage: - if err := c.handlePong(string(payload)); err != nil { - return noFrame, err - } - case PingMessage: - if err := c.handlePing(string(payload)); err != nil { - return noFrame, err - } - case CloseMessage: - closeCode := CloseNoStatusReceived - closeText := "" - if len(payload) >= 2 { - closeCode = int(binary.BigEndian.Uint16(payload)) - if !isValidReceivedCloseCode(closeCode) { - return noFrame, c.handleProtocolError("invalid close code") - } - closeText = string(payload[2:]) - if !utf8.ValidString(closeText) { - return noFrame, c.handleProtocolError("invalid utf8 payload in close frame") - } - } - if err := c.handleClose(closeCode, closeText); err != nil { - return noFrame, err - } - return noFrame, &CloseError{Code: closeCode, Text: closeText} - } - - return frameType, nil -} - -func (c *Conn) handleProtocolError(message string) error { - c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait)) - return errors.New("websocket: " + message) -} - -// NextReader returns the next data message received from the peer. The -// returned messageType is either TextMessage or BinaryMessage. -// -// There can be at most one open reader on a connection. NextReader discards -// the previous message if the application has not already consumed it. -// -// Applications must break out of the application's read loop when this method -// returns a non-nil error value. Errors returned from this method are -// permanent. Once this method returns a non-nil error, all subsequent calls to -// this method return the same error. -func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { - // Close previous reader, only relevant for decompression. - if c.reader != nil { - c.reader.Close() - c.reader = nil - } - - c.messageReader = nil - c.readLength = 0 - - for c.readErr == nil { - frameType, err := c.advanceFrame() - if err != nil { - c.readErr = hideTempErr(err) - break - } - if frameType == TextMessage || frameType == BinaryMessage { - c.messageReader = &messageReader{c} - c.reader = c.messageReader - if c.readDecompress { - c.reader = c.newDecompressionReader(c.reader) - } - return frameType, c.reader, nil - } - } - - // Applications that do handle the error returned from this method spin in - // tight loop on connection failure. To help application developers detect - // this error, panic on repeated reads to the failed connection. - c.readErrCount++ - if c.readErrCount >= 1000 { - panic("repeated read on failed websocket connection") - } - - return noFrame, nil, c.readErr -} - -type messageReader struct{ c *Conn } - -func (r *messageReader) Read(b []byte) (int, error) { - c := r.c - if c.messageReader != r { - return 0, io.EOF - } - - for c.readErr == nil { - - if c.readRemaining > 0 { - if int64(len(b)) > c.readRemaining { - b = b[:c.readRemaining] - } - n, err := c.br.Read(b) - c.readErr = hideTempErr(err) - if c.isServer { - c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n]) - } - c.readRemaining -= int64(n) - if c.readRemaining > 0 && c.readErr == io.EOF { - c.readErr = errUnexpectedEOF - } - return n, c.readErr - } - - if c.readFinal { - c.messageReader = nil - return 0, io.EOF - } - - frameType, err := c.advanceFrame() - switch { - case err != nil: - c.readErr = hideTempErr(err) - case frameType == TextMessage || frameType == BinaryMessage: - c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader") - } - } - - err := c.readErr - if err == io.EOF && c.messageReader == r { - err = errUnexpectedEOF - } - return 0, err -} - -func (r *messageReader) Close() error { - return nil -} - -// ReadMessage is a helper method for getting a reader using NextReader and -// reading from that reader to a buffer. -func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { - var r io.Reader - messageType, r, err = c.NextReader() - if err != nil { - return messageType, nil, err - } - p, err = ioutil.ReadAll(r) - return messageType, p, err -} - -// SetReadDeadline sets the read deadline on the underlying network connection. -// After a read has timed out, the websocket connection state is corrupt and -// all future reads will return an error. A zero value for t means reads will -// not time out. -func (c *Conn) SetReadDeadline(t time.Time) error { - return c.conn.SetReadDeadline(t) -} - -// SetReadLimit sets the maximum size for a message read from the peer. If a -// message exceeds the limit, the connection sends a close message to the peer -// and returns ErrReadLimit to the application. -func (c *Conn) SetReadLimit(limit int64) { - c.readLimit = limit -} - -// CloseHandler returns the current close handler -func (c *Conn) CloseHandler() func(code int, text string) error { - return c.handleClose -} - -// SetCloseHandler sets the handler for close messages received from the peer. -// The code argument to h is the received close code or CloseNoStatusReceived -// if the close message is empty. The default close handler sends a close -// message back to the peer. -// -// The handler function is called from the NextReader, ReadMessage and message -// reader Read methods. The application must read the connection to process -// close messages as described in the section on Control Messages above. -// -// The connection read methods return a CloseError when a close message is -// received. Most applications should handle close messages as part of their -// normal error handling. Applications should only set a close handler when the -// application must perform some action before sending a close message back to -// the peer. -func (c *Conn) SetCloseHandler(h func(code int, text string) error) { - if h == nil { - h = func(code int, text string) error { - message := FormatCloseMessage(code, "") - c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) - return nil - } - } - c.handleClose = h -} - -// PingHandler returns the current ping handler -func (c *Conn) PingHandler() func(appData string) error { - return c.handlePing -} - -// SetPingHandler sets the handler for ping messages received from the peer. -// The appData argument to h is the PING message application data. The default -// ping handler sends a pong to the peer. -// -// The handler function is called from the NextReader, ReadMessage and message -// reader Read methods. The application must read the connection to process -// ping messages as described in the section on Control Messages above. -func (c *Conn) SetPingHandler(h func(appData string) error) { - if h == nil { - h = func(message string) error { - err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait)) - if err == ErrCloseSent { - return nil - } else if e, ok := err.(net.Error); ok && e.Temporary() { - return nil - } - return err - } - } - c.handlePing = h -} - -// PongHandler returns the current pong handler -func (c *Conn) PongHandler() func(appData string) error { - return c.handlePong -} - -// SetPongHandler sets the handler for pong messages received from the peer. -// The appData argument to h is the PONG message application data. The default -// pong handler does nothing. -// -// The handler function is called from the NextReader, ReadMessage and message -// reader Read methods. The application must read the connection to process -// pong messages as described in the section on Control Messages above. -func (c *Conn) SetPongHandler(h func(appData string) error) { - if h == nil { - h = func(string) error { return nil } - } - c.handlePong = h -} - -// UnderlyingConn returns the internal net.Conn. This can be used to further -// modifications to connection specific flags. -func (c *Conn) UnderlyingConn() net.Conn { - return c.conn -} - -// EnableWriteCompression enables and disables write compression of -// subsequent text and binary messages. This function is a noop if -// compression was not negotiated with the peer. -func (c *Conn) EnableWriteCompression(enable bool) { - c.enableWriteCompression = enable -} - -// SetCompressionLevel sets the flate compression level for subsequent text and -// binary messages. This function is a noop if compression was not negotiated -// with the peer. See the compress/flate package for a description of -// compression levels. -func (c *Conn) SetCompressionLevel(level int) error { - if !isValidCompressionLevel(level) { - return errors.New("websocket: invalid compression level") - } - c.compressionLevel = level - return nil -} - -// FormatCloseMessage formats closeCode and text as a WebSocket close message. -// An empty message is returned for code CloseNoStatusReceived. -func FormatCloseMessage(closeCode int, text string) []byte { - if closeCode == CloseNoStatusReceived { - // Return empty message because it's illegal to send - // CloseNoStatusReceived. Return non-nil value in case application - // checks for nil. - return []byte{} - } - buf := make([]byte, 2+len(text)) - binary.BigEndian.PutUint16(buf, uint16(closeCode)) - copy(buf[2:], text) - return buf -} diff --git a/vendor/github.com/gorilla/websocket/conn_read.go b/vendor/github.com/gorilla/websocket/conn_read.go deleted file mode 100644 index 1ea1505..0000000 --- a/vendor/github.com/gorilla/websocket/conn_read.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.5 - -package websocket - -import "io" - -func (c *Conn) read(n int) ([]byte, error) { - p, err := c.br.Peek(n) - if err == io.EOF { - err = errUnexpectedEOF - } - c.br.Discard(len(p)) - return p, err -} diff --git a/vendor/github.com/gorilla/websocket/conn_read_legacy.go b/vendor/github.com/gorilla/websocket/conn_read_legacy.go deleted file mode 100644 index 018541c..0000000 --- a/vendor/github.com/gorilla/websocket/conn_read_legacy.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.5 - -package websocket - -import "io" - -func (c *Conn) read(n int) ([]byte, error) { - p, err := c.br.Peek(n) - if err == io.EOF { - err = errUnexpectedEOF - } - if len(p) > 0 { - // advance over the bytes just read - io.ReadFull(c.br, p) - } - return p, err -} diff --git a/vendor/github.com/gorilla/websocket/conn_write.go b/vendor/github.com/gorilla/websocket/conn_write.go deleted file mode 100644 index a509a21..0000000 --- a/vendor/github.com/gorilla/websocket/conn_write.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.8 - -package websocket - -import "net" - -func (c *Conn) writeBufs(bufs ...[]byte) error { - b := net.Buffers(bufs) - _, err := b.WriteTo(c.conn) - return err -} diff --git a/vendor/github.com/gorilla/websocket/conn_write_legacy.go b/vendor/github.com/gorilla/websocket/conn_write_legacy.go deleted file mode 100644 index 37edaff..0000000 --- a/vendor/github.com/gorilla/websocket/conn_write_legacy.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.8 - -package websocket - -func (c *Conn) writeBufs(bufs ...[]byte) error { - for _, buf := range bufs { - if len(buf) > 0 { - if _, err := c.conn.Write(buf); err != nil { - return err - } - } - } - return nil -} diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go deleted file mode 100644 index dcce1a6..0000000 --- a/vendor/github.com/gorilla/websocket/doc.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package websocket implements the WebSocket protocol defined in RFC 6455. -// -// Overview -// -// The Conn type represents a WebSocket connection. A server application calls -// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn: -// -// var upgrader = websocket.Upgrader{ -// ReadBufferSize: 1024, -// WriteBufferSize: 1024, -// } -// -// func handler(w http.ResponseWriter, r *http.Request) { -// conn, err := upgrader.Upgrade(w, r, nil) -// if err != nil { -// log.Println(err) -// return -// } -// ... Use conn to send and receive messages. -// } -// -// Call the connection's WriteMessage and ReadMessage methods to send and -// receive messages as a slice of bytes. This snippet of code shows how to echo -// messages using these methods: -// -// for { -// messageType, p, err := conn.ReadMessage() -// if err != nil { -// log.Println(err) -// return -// } -// if err := conn.WriteMessage(messageType, p); err != nil { -// log.Println(err) -// return -// } -// } -// -// In above snippet of code, p is a []byte and messageType is an int with value -// websocket.BinaryMessage or websocket.TextMessage. -// -// An application can also send and receive messages using the io.WriteCloser -// and io.Reader interfaces. To send a message, call the connection NextWriter -// method to get an io.WriteCloser, write the message to the writer and close -// the writer when done. To receive a message, call the connection NextReader -// method to get an io.Reader and read until io.EOF is returned. This snippet -// shows how to echo messages using the NextWriter and NextReader methods: -// -// for { -// messageType, r, err := conn.NextReader() -// if err != nil { -// return -// } -// w, err := conn.NextWriter(messageType) -// if err != nil { -// return err -// } -// if _, err := io.Copy(w, r); err != nil { -// return err -// } -// if err := w.Close(); err != nil { -// return err -// } -// } -// -// Data Messages -// -// The WebSocket protocol distinguishes between text and binary data messages. -// Text messages are interpreted as UTF-8 encoded text. The interpretation of -// binary messages is left to the application. -// -// This package uses the TextMessage and BinaryMessage integer constants to -// identify the two data message types. The ReadMessage and NextReader methods -// return the type of the received message. The messageType argument to the -// WriteMessage and NextWriter methods specifies the type of a sent message. -// -// It is the application's responsibility to ensure that text messages are -// valid UTF-8 encoded text. -// -// Control Messages -// -// The WebSocket protocol defines three types of control messages: close, ping -// and pong. Call the connection WriteControl, WriteMessage or NextWriter -// methods to send a control message to the peer. -// -// Connections handle received close messages by calling the handler function -// set with the SetCloseHandler method and by returning a *CloseError from the -// NextReader, ReadMessage or the message Read method. The default close -// handler sends a close message to the peer. -// -// Connections handle received ping messages by calling the handler function -// set with the SetPingHandler method. The default ping handler sends a pong -// message to the peer. -// -// Connections handle received pong messages by calling the handler function -// set with the SetPongHandler method. The default pong handler does nothing. -// If an application sends ping messages, then the application should set a -// pong handler to receive the corresponding pong. -// -// The control message handler functions are called from the NextReader, -// ReadMessage and message reader Read methods. The default close and ping -// handlers can block these methods for a short time when the handler writes to -// the connection. -// -// The application must read the connection to process close, ping and pong -// messages sent from the peer. If the application is not otherwise interested -// in messages from the peer, then the application should start a goroutine to -// read and discard messages from the peer. A simple example is: -// -// func readLoop(c *websocket.Conn) { -// for { -// if _, _, err := c.NextReader(); err != nil { -// c.Close() -// break -// } -// } -// } -// -// Concurrency -// -// Connections support one concurrent reader and one concurrent writer. -// -// Applications are responsible for ensuring that no more than one goroutine -// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, -// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and -// that no more than one goroutine calls the read methods (NextReader, -// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) -// concurrently. -// -// The Close and WriteControl methods can be called concurrently with all other -// methods. -// -// Origin Considerations -// -// Web browsers allow Javascript applications to open a WebSocket connection to -// any host. It's up to the server to enforce an origin policy using the Origin -// request header sent by the browser. -// -// The Upgrader calls the function specified in the CheckOrigin field to check -// the origin. If the CheckOrigin function returns false, then the Upgrade -// method fails the WebSocket handshake with HTTP status 403. -// -// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail -// the handshake if the Origin request header is present and the Origin host is -// not equal to the Host request header. -// -// The deprecated package-level Upgrade function does not perform origin -// checking. The application is responsible for checking the Origin header -// before calling the Upgrade function. -// -// Compression EXPERIMENTAL -// -// Per message compression extensions (RFC 7692) are experimentally supported -// by this package in a limited capacity. Setting the EnableCompression option -// to true in Dialer or Upgrader will attempt to negotiate per message deflate -// support. -// -// var upgrader = websocket.Upgrader{ -// EnableCompression: true, -// } -// -// If compression was successfully negotiated with the connection's peer, any -// message received in compressed form will be automatically decompressed. -// All Read methods will return uncompressed bytes. -// -// Per message compression of messages written to a connection can be enabled -// or disabled by calling the corresponding Conn method: -// -// conn.EnableWriteCompression(false) -// -// Currently this package does not support compression with "context takeover". -// This means that messages must be compressed and decompressed in isolation, -// without retaining sliding window or dictionary state across messages. For -// more details refer to RFC 7692. -// -// Use of compression is experimental and may result in decreased performance. -package websocket diff --git a/vendor/github.com/gorilla/websocket/json.go b/vendor/github.com/gorilla/websocket/json.go deleted file mode 100644 index dc2c1f6..0000000 --- a/vendor/github.com/gorilla/websocket/json.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "encoding/json" - "io" -) - -// WriteJSON writes the JSON encoding of v as a message. -// -// Deprecated: Use c.WriteJSON instead. -func WriteJSON(c *Conn, v interface{}) error { - return c.WriteJSON(v) -} - -// WriteJSON writes the JSON encoding of v as a message. -// -// See the documentation for encoding/json Marshal for details about the -// conversion of Go values to JSON. -func (c *Conn) WriteJSON(v interface{}) error { - w, err := c.NextWriter(TextMessage) - if err != nil { - return err - } - err1 := json.NewEncoder(w).Encode(v) - err2 := w.Close() - if err1 != nil { - return err1 - } - return err2 -} - -// ReadJSON reads the next JSON-encoded message from the connection and stores -// it in the value pointed to by v. -// -// Deprecated: Use c.ReadJSON instead. -func ReadJSON(c *Conn, v interface{}) error { - return c.ReadJSON(v) -} - -// ReadJSON reads the next JSON-encoded message from the connection and stores -// it in the value pointed to by v. -// -// See the documentation for the encoding/json Unmarshal function for details -// about the conversion of JSON to a Go value. -func (c *Conn) ReadJSON(v interface{}) error { - _, r, err := c.NextReader() - if err != nil { - return err - } - err = json.NewDecoder(r).Decode(v) - if err == io.EOF { - // One value is expected in the message. - err = io.ErrUnexpectedEOF - } - return err -} diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go deleted file mode 100644 index 577fce9..0000000 --- a/vendor/github.com/gorilla/websocket/mask.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of -// this source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// +build !appengine - -package websocket - -import "unsafe" - -const wordSize = int(unsafe.Sizeof(uintptr(0))) - -func maskBytes(key [4]byte, pos int, b []byte) int { - // Mask one byte at a time for small buffers. - if len(b) < 2*wordSize { - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - return pos & 3 - } - - // Mask one byte at a time to word boundary. - if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 { - n = wordSize - n - for i := range b[:n] { - b[i] ^= key[pos&3] - pos++ - } - b = b[n:] - } - - // Create aligned word size key. - var k [wordSize]byte - for i := range k { - k[i] = key[(pos+i)&3] - } - kw := *(*uintptr)(unsafe.Pointer(&k)) - - // Mask one word at a time. - n := (len(b) / wordSize) * wordSize - for i := 0; i < n; i += wordSize { - *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw - } - - // Mask one byte at a time for remaining bytes. - b = b[n:] - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - - return pos & 3 -} diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go deleted file mode 100644 index 2aac060..0000000 --- a/vendor/github.com/gorilla/websocket/mask_safe.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of -// this source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// +build appengine - -package websocket - -func maskBytes(key [4]byte, pos int, b []byte) int { - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - return pos & 3 -} diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go deleted file mode 100644 index 1efffbd..0000000 --- a/vendor/github.com/gorilla/websocket/prepared.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bytes" - "net" - "sync" - "time" -) - -// PreparedMessage caches on the wire representations of a message payload. -// Use PreparedMessage to efficiently send a message payload to multiple -// connections. PreparedMessage is especially useful when compression is used -// because the CPU and memory expensive compression operation can be executed -// once for a given set of compression options. -type PreparedMessage struct { - messageType int - data []byte - err error - mu sync.Mutex - frames map[prepareKey]*preparedFrame -} - -// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage. -type prepareKey struct { - isServer bool - compress bool - compressionLevel int -} - -// preparedFrame contains data in wire representation. -type preparedFrame struct { - once sync.Once - data []byte -} - -// NewPreparedMessage returns an initialized PreparedMessage. You can then send -// it to connection using WritePreparedMessage method. Valid wire -// representation will be calculated lazily only once for a set of current -// connection options. -func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) { - pm := &PreparedMessage{ - messageType: messageType, - frames: make(map[prepareKey]*preparedFrame), - data: data, - } - - // Prepare a plain server frame. - _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false}) - if err != nil { - return nil, err - } - - // To protect against caller modifying the data argument, remember the data - // copied to the plain server frame. - pm.data = frameData[len(frameData)-len(data):] - return pm, nil -} - -func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { - pm.mu.Lock() - frame, ok := pm.frames[key] - if !ok { - frame = &preparedFrame{} - pm.frames[key] = frame - } - pm.mu.Unlock() - - var err error - frame.once.Do(func() { - // Prepare a frame using a 'fake' connection. - // TODO: Refactor code in conn.go to allow more direct construction of - // the frame. - mu := make(chan bool, 1) - mu <- true - var nc prepareConn - c := &Conn{ - conn: &nc, - mu: mu, - isServer: key.isServer, - compressionLevel: key.compressionLevel, - enableWriteCompression: true, - writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize), - } - if key.compress { - c.newCompressionWriter = compressNoContextTakeover - } - err = c.WriteMessage(pm.messageType, pm.data) - frame.data = nc.buf.Bytes() - }) - return pm.messageType, frame.data, err -} - -type prepareConn struct { - buf bytes.Buffer - net.Conn -} - -func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) } -func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil } diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go deleted file mode 100644 index bf2478e..0000000 --- a/vendor/github.com/gorilla/websocket/proxy.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "encoding/base64" - "errors" - "net" - "net/http" - "net/url" - "strings" -) - -type netDialerFunc func(network, addr string) (net.Conn, error) - -func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { - return fn(network, addr) -} - -func init() { - proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { - return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil - }) -} - -type httpProxyDialer struct { - proxyURL *url.URL - fowardDial func(network, addr string) (net.Conn, error) -} - -func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { - hostPort, _ := hostPortNoPort(hpd.proxyURL) - conn, err := hpd.fowardDial(network, hostPort) - if err != nil { - return nil, err - } - - connectHeader := make(http.Header) - if user := hpd.proxyURL.User; user != nil { - proxyUser := user.Username() - if proxyPassword, passwordSet := user.Password(); passwordSet { - credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword)) - connectHeader.Set("Proxy-Authorization", "Basic "+credential) - } - } - - connectReq := &http.Request{ - Method: "CONNECT", - URL: &url.URL{Opaque: addr}, - Host: addr, - Header: connectHeader, - } - - if err := connectReq.Write(conn); err != nil { - conn.Close() - return nil, err - } - - // Read response. It's OK to use and discard buffered reader here becaue - // the remote server does not speak until spoken to. - br := bufio.NewReader(conn) - resp, err := http.ReadResponse(br, connectReq) - if err != nil { - conn.Close() - return nil, err - } - - if resp.StatusCode != 200 { - conn.Close() - f := strings.SplitN(resp.Status, " ", 2) - return nil, errors.New(f[1]) - } - return conn, nil -} diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go deleted file mode 100644 index aee2705..0000000 --- a/vendor/github.com/gorilla/websocket/server.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "errors" - "net" - "net/http" - "net/url" - "strings" - "time" -) - -// HandshakeError describes an error with the handshake from the peer. -type HandshakeError struct { - message string -} - -func (e HandshakeError) Error() string { return e.message } - -// Upgrader specifies parameters for upgrading an HTTP connection to a -// WebSocket connection. -type Upgrader struct { - // HandshakeTimeout specifies the duration for the handshake to complete. - HandshakeTimeout time.Duration - - // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer - // size is zero, then buffers allocated by the HTTP server are used. The - // I/O buffer sizes do not limit the size of the messages that can be sent - // or received. - ReadBufferSize, WriteBufferSize int - - // Subprotocols specifies the server's supported protocols in order of - // preference. If this field is set, then the Upgrade method negotiates a - // subprotocol by selecting the first match in this list with a protocol - // requested by the client. - Subprotocols []string - - // Error specifies the function for generating HTTP error responses. If Error - // is nil, then http.Error is used to generate the HTTP response. - Error func(w http.ResponseWriter, r *http.Request, status int, reason error) - - // CheckOrigin returns true if the request Origin header is acceptable. If - // CheckOrigin is nil, then a safe default is used: return false if the - // Origin request header is present and the origin host is not equal to - // request Host header. - // - // A CheckOrigin function should carefully validate the request origin to - // prevent cross-site request forgery. - CheckOrigin func(r *http.Request) bool - - // EnableCompression specify if the server should attempt to negotiate per - // message compression (RFC 7692). Setting this value to true does not - // guarantee that compression will be supported. Currently only "no context - // takeover" modes are supported. - EnableCompression bool -} - -func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) { - err := HandshakeError{reason} - if u.Error != nil { - u.Error(w, r, status, err) - } else { - w.Header().Set("Sec-Websocket-Version", "13") - http.Error(w, http.StatusText(status), status) - } - return nil, err -} - -// checkSameOrigin returns true if the origin is not set or is equal to the request host. -func checkSameOrigin(r *http.Request) bool { - origin := r.Header["Origin"] - if len(origin) == 0 { - return true - } - u, err := url.Parse(origin[0]) - if err != nil { - return false - } - return equalASCIIFold(u.Host, r.Host) -} - -func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string { - if u.Subprotocols != nil { - clientProtocols := Subprotocols(r) - for _, serverProtocol := range u.Subprotocols { - for _, clientProtocol := range clientProtocols { - if clientProtocol == serverProtocol { - return clientProtocol - } - } - } - } else if responseHeader != nil { - return responseHeader.Get("Sec-Websocket-Protocol") - } - return "" -} - -// Upgrade upgrades the HTTP server connection to the WebSocket protocol. -// -// The responseHeader is included in the response to the client's upgrade -// request. Use the responseHeader to specify cookies (Set-Cookie) and the -// application negotiated subprotocol (Sec-WebSocket-Protocol). -// -// If the upgrade fails, then Upgrade replies to the client with an HTTP error -// response. -func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { - const badHandshake = "websocket: the client is not using the websocket protocol: " - - if !tokenListContainsValue(r.Header, "Connection", "upgrade") { - return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header") - } - - if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { - return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header") - } - - if r.Method != "GET" { - return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET") - } - - if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") - } - - if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { - return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported") - } - - checkOrigin := u.CheckOrigin - if checkOrigin == nil { - checkOrigin = checkSameOrigin - } - if !checkOrigin(r) { - return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin") - } - - challengeKey := r.Header.Get("Sec-Websocket-Key") - if challengeKey == "" { - return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank") - } - - subprotocol := u.selectSubprotocol(r, responseHeader) - - // Negotiate PMCE - var compress bool - if u.EnableCompression { - for _, ext := range parseExtensions(r.Header) { - if ext[""] != "permessage-deflate" { - continue - } - compress = true - break - } - } - - var ( - netConn net.Conn - err error - ) - - h, ok := w.(http.Hijacker) - if !ok { - return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") - } - var brw *bufio.ReadWriter - netConn, brw, err = h.Hijack() - if err != nil { - return u.returnError(w, r, http.StatusInternalServerError, err.Error()) - } - - if brw.Reader.Buffered() > 0 { - netConn.Close() - return nil, errors.New("websocket: client sent data before handshake is complete") - } - - c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw) - c.subprotocol = subprotocol - - if compress { - c.newCompressionWriter = compressNoContextTakeover - c.newDecompressionReader = decompressNoContextTakeover - } - - p := c.writeBuf[:0] - p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) - p = append(p, computeAcceptKey(challengeKey)...) - p = append(p, "\r\n"...) - if c.subprotocol != "" { - p = append(p, "Sec-WebSocket-Protocol: "...) - p = append(p, c.subprotocol...) - p = append(p, "\r\n"...) - } - if compress { - p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...) - } - for k, vs := range responseHeader { - if k == "Sec-Websocket-Protocol" { - continue - } - for _, v := range vs { - p = append(p, k...) - p = append(p, ": "...) - for i := 0; i < len(v); i++ { - b := v[i] - if b <= 31 { - // prevent response splitting. - b = ' ' - } - p = append(p, b) - } - p = append(p, "\r\n"...) - } - } - p = append(p, "\r\n"...) - - // Clear deadlines set by HTTP server. - netConn.SetDeadline(time.Time{}) - - if u.HandshakeTimeout > 0 { - netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) - } - if _, err = netConn.Write(p); err != nil { - netConn.Close() - return nil, err - } - if u.HandshakeTimeout > 0 { - netConn.SetWriteDeadline(time.Time{}) - } - - return c, nil -} - -// Upgrade upgrades the HTTP server connection to the WebSocket protocol. -// -// Deprecated: Use websocket.Upgrader instead. -// -// Upgrade does not perform origin checking. The application is responsible for -// checking the Origin header before calling Upgrade. An example implementation -// of the same origin policy check is: -// -// if req.Header.Get("Origin") != "http://"+req.Host { -// http.Error(w, "Origin not allowed", http.StatusForbidden) -// return -// } -// -// If the endpoint supports subprotocols, then the application is responsible -// for negotiating the protocol used on the connection. Use the Subprotocols() -// function to get the subprotocols requested by the client. Use the -// Sec-Websocket-Protocol response header to specify the subprotocol selected -// by the application. -// -// The responseHeader is included in the response to the client's upgrade -// request. Use the responseHeader to specify cookies (Set-Cookie) and the -// negotiated subprotocol (Sec-Websocket-Protocol). -// -// The connection buffers IO to the underlying network connection. The -// readBufSize and writeBufSize parameters specify the size of the buffers to -// use. Messages can be larger than the buffers. -// -// If the request is not a valid WebSocket handshake, then Upgrade returns an -// error of type HandshakeError. Applications should handle this error by -// replying to the client with an HTTP error response. -func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) { - u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize} - u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) { - // don't return errors to maintain backwards compatibility - } - u.CheckOrigin = func(r *http.Request) bool { - // allow all connections by default - return true - } - return u.Upgrade(w, r, responseHeader) -} - -// Subprotocols returns the subprotocols requested by the client in the -// Sec-Websocket-Protocol header. -func Subprotocols(r *http.Request) []string { - h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol")) - if h == "" { - return nil - } - protocols := strings.Split(h, ",") - for i := range protocols { - protocols[i] = strings.TrimSpace(protocols[i]) - } - return protocols -} - -// IsWebSocketUpgrade returns true if the client requested upgrade to the -// WebSocket protocol. -func IsWebSocketUpgrade(r *http.Request) bool { - return tokenListContainsValue(r.Header, "Connection", "upgrade") && - tokenListContainsValue(r.Header, "Upgrade", "websocket") -} diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go deleted file mode 100644 index 385fa01..0000000 --- a/vendor/github.com/gorilla/websocket/util.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "crypto/rand" - "crypto/sha1" - "encoding/base64" - "io" - "net/http" - "strings" - "unicode/utf8" -) - -var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") - -func computeAcceptKey(challengeKey string) string { - h := sha1.New() - h.Write([]byte(challengeKey)) - h.Write(keyGUID) - return base64.StdEncoding.EncodeToString(h.Sum(nil)) -} - -func generateChallengeKey() (string, error) { - p := make([]byte, 16) - if _, err := io.ReadFull(rand.Reader, p); err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(p), nil -} - -// Octet types from RFC 2616. -var octetTypes [256]byte - -const ( - isTokenOctet = 1 << iota - isSpaceOctet -) - -func init() { - // From RFC 2616 - // - // OCTET = - // CHAR = - // CTL = - // CR = - // LF = - // SP = - // HT = - // <"> = - // CRLF = CR LF - // LWS = [CRLF] 1*( SP | HT ) - // TEXT = - // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> - // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT - // token = 1* - // qdtext = > - - for c := 0; c < 256; c++ { - var t byte - isCtl := c <= 31 || c == 127 - isChar := 0 <= c && c <= 127 - isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 - if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { - t |= isSpaceOctet - } - if isChar && !isCtl && !isSeparator { - t |= isTokenOctet - } - octetTypes[c] = t - } -} - -func skipSpace(s string) (rest string) { - i := 0 - for ; i < len(s); i++ { - if octetTypes[s[i]]&isSpaceOctet == 0 { - break - } - } - return s[i:] -} - -func nextToken(s string) (token, rest string) { - i := 0 - for ; i < len(s); i++ { - if octetTypes[s[i]]&isTokenOctet == 0 { - break - } - } - return s[:i], s[i:] -} - -func nextTokenOrQuoted(s string) (value string, rest string) { - if !strings.HasPrefix(s, "\"") { - return nextToken(s) - } - s = s[1:] - for i := 0; i < len(s); i++ { - switch s[i] { - case '"': - return s[:i], s[i+1:] - case '\\': - p := make([]byte, len(s)-1) - j := copy(p, s[:i]) - escape := true - for i = i + 1; i < len(s); i++ { - b := s[i] - switch { - case escape: - escape = false - p[j] = b - j++ - case b == '\\': - escape = true - case b == '"': - return string(p[:j]), s[i+1:] - default: - p[j] = b - j++ - } - } - return "", "" - } - } - return "", "" -} - -// equalASCIIFold returns true if s is equal to t with ASCII case folding. -func equalASCIIFold(s, t string) bool { - for s != "" && t != "" { - sr, size := utf8.DecodeRuneInString(s) - s = s[size:] - tr, size := utf8.DecodeRuneInString(t) - t = t[size:] - if sr == tr { - continue - } - if 'A' <= sr && sr <= 'Z' { - sr = sr + 'a' - 'A' - } - if 'A' <= tr && tr <= 'Z' { - tr = tr + 'a' - 'A' - } - if sr != tr { - return false - } - } - return s == t -} - -// tokenListContainsValue returns true if the 1#token header with the given -// name contains a token equal to value with ASCII case folding. -func tokenListContainsValue(header http.Header, name string, value string) bool { -headers: - for _, s := range header[name] { - for { - var t string - t, s = nextToken(skipSpace(s)) - if t == "" { - continue headers - } - s = skipSpace(s) - if s != "" && s[0] != ',' { - continue headers - } - if equalASCIIFold(t, value) { - return true - } - if s == "" { - continue headers - } - s = s[1:] - } - } - return false -} - -// parseExtensiosn parses WebSocket extensions from a header. -func parseExtensions(header http.Header) []map[string]string { - // From RFC 6455: - // - // Sec-WebSocket-Extensions = extension-list - // extension-list = 1#extension - // extension = extension-token *( ";" extension-param ) - // extension-token = registered-token - // registered-token = token - // extension-param = token [ "=" (token | quoted-string) ] - // ;When using the quoted-string syntax variant, the value - // ;after quoted-string unescaping MUST conform to the - // ;'token' ABNF. - - var result []map[string]string -headers: - for _, s := range header["Sec-Websocket-Extensions"] { - for { - var t string - t, s = nextToken(skipSpace(s)) - if t == "" { - continue headers - } - ext := map[string]string{"": t} - for { - s = skipSpace(s) - if !strings.HasPrefix(s, ";") { - break - } - var k string - k, s = nextToken(skipSpace(s[1:])) - if k == "" { - continue headers - } - s = skipSpace(s) - var v string - if strings.HasPrefix(s, "=") { - v, s = nextTokenOrQuoted(skipSpace(s[1:])) - s = skipSpace(s) - } - if s != "" && s[0] != ',' && s[0] != ';' { - continue headers - } - ext[k] = v - } - if s != "" && s[0] != ',' { - continue headers - } - result = append(result, ext) - if s == "" { - continue headers - } - s = s[1:] - } - } - return result -} diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go deleted file mode 100644 index 2e668f6..0000000 --- a/vendor/github.com/gorilla/websocket/x_net_proxy.go +++ /dev/null @@ -1,473 +0,0 @@ -// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. -//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy - -// Package proxy provides support for a variety of protocols to proxy network -// data. -// - -package websocket - -import ( - "errors" - "io" - "net" - "net/url" - "os" - "strconv" - "strings" - "sync" -) - -type proxy_direct struct{} - -// Direct is a direct proxy: one that makes network connections directly. -var proxy_Direct = proxy_direct{} - -func (proxy_direct) Dial(network, addr string) (net.Conn, error) { - return net.Dial(network, addr) -} - -// A PerHost directs connections to a default Dialer unless the host name -// requested matches one of a number of exceptions. -type proxy_PerHost struct { - def, bypass proxy_Dialer - - bypassNetworks []*net.IPNet - bypassIPs []net.IP - bypassZones []string - bypassHosts []string -} - -// NewPerHost returns a PerHost Dialer that directs connections to either -// defaultDialer or bypass, depending on whether the connection matches one of -// the configured rules. -func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost { - return &proxy_PerHost{ - def: defaultDialer, - bypass: bypass, - } -} - -// Dial connects to the address addr on the given network through either -// defaultDialer or bypass. -func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - - return p.dialerForRequest(host).Dial(network, addr) -} - -func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer { - if ip := net.ParseIP(host); ip != nil { - for _, net := range p.bypassNetworks { - if net.Contains(ip) { - return p.bypass - } - } - for _, bypassIP := range p.bypassIPs { - if bypassIP.Equal(ip) { - return p.bypass - } - } - return p.def - } - - for _, zone := range p.bypassZones { - if strings.HasSuffix(host, zone) { - return p.bypass - } - if host == zone[1:] { - // For a zone ".example.com", we match "example.com" - // too. - return p.bypass - } - } - for _, bypassHost := range p.bypassHosts { - if bypassHost == host { - return p.bypass - } - } - return p.def -} - -// AddFromString parses a string that contains comma-separated values -// specifying hosts that should use the bypass proxy. Each value is either an -// IP address, a CIDR range, a zone (*.example.com) or a host name -// (localhost). A best effort is made to parse the string and errors are -// ignored. -func (p *proxy_PerHost) AddFromString(s string) { - hosts := strings.Split(s, ",") - for _, host := range hosts { - host = strings.TrimSpace(host) - if len(host) == 0 { - continue - } - if strings.Contains(host, "/") { - // We assume that it's a CIDR address like 127.0.0.0/8 - if _, net, err := net.ParseCIDR(host); err == nil { - p.AddNetwork(net) - } - continue - } - if ip := net.ParseIP(host); ip != nil { - p.AddIP(ip) - continue - } - if strings.HasPrefix(host, "*.") { - p.AddZone(host[1:]) - continue - } - p.AddHost(host) - } -} - -// AddIP specifies an IP address that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match an IP. -func (p *proxy_PerHost) AddIP(ip net.IP) { - p.bypassIPs = append(p.bypassIPs, ip) -} - -// AddNetwork specifies an IP range that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match. -func (p *proxy_PerHost) AddNetwork(net *net.IPNet) { - p.bypassNetworks = append(p.bypassNetworks, net) -} - -// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of -// "example.com" matches "example.com" and all of its subdomains. -func (p *proxy_PerHost) AddZone(zone string) { - if strings.HasSuffix(zone, ".") { - zone = zone[:len(zone)-1] - } - if !strings.HasPrefix(zone, ".") { - zone = "." + zone - } - p.bypassZones = append(p.bypassZones, zone) -} - -// AddHost specifies a host name that will use the bypass proxy. -func (p *proxy_PerHost) AddHost(host string) { - if strings.HasSuffix(host, ".") { - host = host[:len(host)-1] - } - p.bypassHosts = append(p.bypassHosts, host) -} - -// A Dialer is a means to establish a connection. -type proxy_Dialer interface { - // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, err error) -} - -// Auth contains authentication parameters that specific Dialers may require. -type proxy_Auth struct { - User, Password string -} - -// FromEnvironment returns the dialer specified by the proxy related variables in -// the environment. -func proxy_FromEnvironment() proxy_Dialer { - allProxy := proxy_allProxyEnv.Get() - if len(allProxy) == 0 { - return proxy_Direct - } - - proxyURL, err := url.Parse(allProxy) - if err != nil { - return proxy_Direct - } - proxy, err := proxy_FromURL(proxyURL, proxy_Direct) - if err != nil { - return proxy_Direct - } - - noProxy := proxy_noProxyEnv.Get() - if len(noProxy) == 0 { - return proxy - } - - perHost := proxy_NewPerHost(proxy, proxy_Direct) - perHost.AddFromString(noProxy) - return perHost -} - -// proxySchemes is a map from URL schemes to a function that creates a Dialer -// from a URL with such a scheme. -var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error) - -// RegisterDialerType takes a URL scheme and a function to generate Dialers from -// a URL with that scheme and a forwarding Dialer. Registered schemes are used -// by FromURL. -func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) { - if proxy_proxySchemes == nil { - proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) - } - proxy_proxySchemes[scheme] = f -} - -// FromURL returns a Dialer given a URL specification and an underlying -// Dialer for it to make network requests. -func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) { - var auth *proxy_Auth - if u.User != nil { - auth = new(proxy_Auth) - auth.User = u.User.Username() - if p, ok := u.User.Password(); ok { - auth.Password = p - } - } - - switch u.Scheme { - case "socks5": - return proxy_SOCKS5("tcp", u.Host, auth, forward) - } - - // If the scheme doesn't match any of the built-in schemes, see if it - // was registered by another package. - if proxy_proxySchemes != nil { - if f, ok := proxy_proxySchemes[u.Scheme]; ok { - return f(u, forward) - } - } - - return nil, errors.New("proxy: unknown scheme: " + u.Scheme) -} - -var ( - proxy_allProxyEnv = &proxy_envOnce{ - names: []string{"ALL_PROXY", "all_proxy"}, - } - proxy_noProxyEnv = &proxy_envOnce{ - names: []string{"NO_PROXY", "no_proxy"}, - } -) - -// envOnce looks up an environment variable (optionally by multiple -// names) once. It mitigates expensive lookups on some platforms -// (e.g. Windows). -// (Borrowed from net/http/transport.go) -type proxy_envOnce struct { - names []string - once sync.Once - val string -} - -func (e *proxy_envOnce) Get() string { - e.once.Do(e.init) - return e.val -} - -func (e *proxy_envOnce) init() { - for _, n := range e.names { - e.val = os.Getenv(n) - if e.val != "" { - return - } - } -} - -// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address -// with an optional username and password. See RFC 1928 and RFC 1929. -func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) { - s := &proxy_socks5{ - network: network, - addr: addr, - forward: forward, - } - if auth != nil { - s.user = auth.User - s.password = auth.Password - } - - return s, nil -} - -type proxy_socks5 struct { - user, password string - network, addr string - forward proxy_Dialer -} - -const proxy_socks5Version = 5 - -const ( - proxy_socks5AuthNone = 0 - proxy_socks5AuthPassword = 2 -) - -const proxy_socks5Connect = 1 - -const ( - proxy_socks5IP4 = 1 - proxy_socks5Domain = 3 - proxy_socks5IP6 = 4 -) - -var proxy_socks5Errors = []string{ - "", - "general failure", - "connection forbidden", - "network unreachable", - "host unreachable", - "connection refused", - "TTL expired", - "command not supported", - "address type not supported", -} - -// Dial connects to the address addr on the given network via the SOCKS5 proxy. -func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) { - switch network { - case "tcp", "tcp6", "tcp4": - default: - return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network) - } - - conn, err := s.forward.Dial(s.network, s.addr) - if err != nil { - return nil, err - } - if err := s.connect(conn, addr); err != nil { - conn.Close() - return nil, err - } - return conn, nil -} - -// connect takes an existing connection to a socks5 proxy server, -// and commands the server to extend that connection to target, -// which must be a canonical address with a host and port. -func (s *proxy_socks5) connect(conn net.Conn, target string) error { - host, portStr, err := net.SplitHostPort(target) - if err != nil { - return err - } - - port, err := strconv.Atoi(portStr) - if err != nil { - return errors.New("proxy: failed to parse port number: " + portStr) - } - if port < 1 || port > 0xffff { - return errors.New("proxy: port number out of range: " + portStr) - } - - // the size here is just an estimate - buf := make([]byte, 0, 6+len(host)) - - buf = append(buf, proxy_socks5Version) - if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { - buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword) - } else { - buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone) - } - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - if buf[0] != 5 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) - } - if buf[1] == 0xff { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") - } - - // See RFC 1929 - if buf[1] == proxy_socks5AuthPassword { - buf = buf[:0] - buf = append(buf, 1 /* password protocol version */) - buf = append(buf, uint8(len(s.user))) - buf = append(buf, s.user...) - buf = append(buf, uint8(len(s.password))) - buf = append(buf, s.password...) - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if buf[1] != 0 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") - } - } - - buf = buf[:0] - buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */) - - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - buf = append(buf, proxy_socks5IP4) - ip = ip4 - } else { - buf = append(buf, proxy_socks5IP6) - } - buf = append(buf, ip...) - } else { - if len(host) > 255 { - return errors.New("proxy: destination host name too long: " + host) - } - buf = append(buf, proxy_socks5Domain) - buf = append(buf, byte(len(host))) - buf = append(buf, host...) - } - buf = append(buf, byte(port>>8), byte(port)) - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:4]); err != nil { - return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - failure := "unknown error" - if int(buf[1]) < len(proxy_socks5Errors) { - failure = proxy_socks5Errors[buf[1]] - } - - if len(failure) > 0 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) - } - - bytesToDiscard := 0 - switch buf[3] { - case proxy_socks5IP4: - bytesToDiscard = net.IPv4len - case proxy_socks5IP6: - bytesToDiscard = net.IPv6len - case proxy_socks5Domain: - _, err := io.ReadFull(conn, buf[:1]) - if err != nil { - return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - bytesToDiscard = int(buf[0]) - default: - return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) - } - - if cap(buf) < bytesToDiscard { - buf = make([]byte, bytesToDiscard) - } else { - buf = buf[:bytesToDiscard] - } - if _, err := io.ReadFull(conn, buf); err != nil { - return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - // Also need to discard the port number - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - return nil -} diff --git a/vendor/github.com/jinzhu/inflection/LICENSE b/vendor/github.com/jinzhu/inflection/LICENSE deleted file mode 100644 index a1ca9a0..0000000 --- a/vendor/github.com/jinzhu/inflection/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 - Jinzhu - -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. diff --git a/vendor/github.com/jinzhu/inflection/README.md b/vendor/github.com/jinzhu/inflection/README.md deleted file mode 100644 index a3de336..0000000 --- a/vendor/github.com/jinzhu/inflection/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Inflection - -Inflection pluralizes and singularizes English nouns - -[![wercker status](https://app.wercker.com/status/f8c7432b097d1f4ce636879670be0930/s/master "wercker status")](https://app.wercker.com/project/byKey/f8c7432b097d1f4ce636879670be0930) - -## Basic Usage - -```go -inflection.Plural("person") => "people" -inflection.Plural("Person") => "People" -inflection.Plural("PERSON") => "PEOPLE" -inflection.Plural("bus") => "buses" -inflection.Plural("BUS") => "BUSES" -inflection.Plural("Bus") => "Buses" - -inflection.Singular("people") => "person" -inflection.Singular("People") => "Person" -inflection.Singular("PEOPLE") => "PERSON" -inflection.Singular("buses") => "bus" -inflection.Singular("BUSES") => "BUS" -inflection.Singular("Buses") => "Bus" - -inflection.Plural("FancyPerson") => "FancyPeople" -inflection.Singular("FancyPeople") => "FancyPerson" -``` - -## Register Rules - -Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) - -If you want to register more rules, follow: - -``` -inflection.AddUncountable("fish") -inflection.AddIrregular("person", "people") -inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" -inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" -``` - -## Contributing - -You can help to make the project better, check out [http://gorm.io/contribute.html](http://gorm.io/contribute.html) for things you can do. - -## Author - -**jinzhu** - -* -* -* - -## License - -Released under the [MIT License](http://www.opensource.org/licenses/MIT). diff --git a/vendor/github.com/jinzhu/inflection/inflections.go b/vendor/github.com/jinzhu/inflection/inflections.go deleted file mode 100644 index 606263b..0000000 --- a/vendor/github.com/jinzhu/inflection/inflections.go +++ /dev/null @@ -1,273 +0,0 @@ -/* -Package inflection pluralizes and singularizes English nouns. - - inflection.Plural("person") => "people" - inflection.Plural("Person") => "People" - inflection.Plural("PERSON") => "PEOPLE" - - inflection.Singular("people") => "person" - inflection.Singular("People") => "Person" - inflection.Singular("PEOPLE") => "PERSON" - - inflection.Plural("FancyPerson") => "FancydPeople" - inflection.Singular("FancyPeople") => "FancydPerson" - -Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) - -If you want to register more rules, follow: - - inflection.AddUncountable("fish") - inflection.AddIrregular("person", "people") - inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" - inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" -*/ -package inflection - -import ( - "regexp" - "strings" -) - -type inflection struct { - regexp *regexp.Regexp - replace string -} - -// Regular is a regexp find replace inflection -type Regular struct { - find string - replace string -} - -// Irregular is a hard replace inflection, -// containing both singular and plural forms -type Irregular struct { - singular string - plural string -} - -// RegularSlice is a slice of Regular inflections -type RegularSlice []Regular - -// IrregularSlice is a slice of Irregular inflections -type IrregularSlice []Irregular - -var pluralInflections = RegularSlice{ - {"([a-z])$", "${1}s"}, - {"s$", "s"}, - {"^(ax|test)is$", "${1}es"}, - {"(octop|vir)us$", "${1}i"}, - {"(octop|vir)i$", "${1}i"}, - {"(alias|status)$", "${1}es"}, - {"(bu)s$", "${1}ses"}, - {"(buffal|tomat)o$", "${1}oes"}, - {"([ti])um$", "${1}a"}, - {"([ti])a$", "${1}a"}, - {"sis$", "ses"}, - {"(?:([^f])fe|([lr])f)$", "${1}${2}ves"}, - {"(hive)$", "${1}s"}, - {"([^aeiouy]|qu)y$", "${1}ies"}, - {"(x|ch|ss|sh)$", "${1}es"}, - {"(matr|vert|ind)(?:ix|ex)$", "${1}ices"}, - {"^(m|l)ouse$", "${1}ice"}, - {"^(m|l)ice$", "${1}ice"}, - {"^(ox)$", "${1}en"}, - {"^(oxen)$", "${1}"}, - {"(quiz)$", "${1}zes"}, -} - -var singularInflections = RegularSlice{ - {"s$", ""}, - {"(ss)$", "${1}"}, - {"(n)ews$", "${1}ews"}, - {"([ti])a$", "${1}um"}, - {"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"}, - {"(^analy)(sis|ses)$", "${1}sis"}, - {"([^f])ves$", "${1}fe"}, - {"(hive)s$", "${1}"}, - {"(tive)s$", "${1}"}, - {"([lr])ves$", "${1}f"}, - {"([^aeiouy]|qu)ies$", "${1}y"}, - {"(s)eries$", "${1}eries"}, - {"(m)ovies$", "${1}ovie"}, - {"(c)ookies$", "${1}ookie"}, - {"(x|ch|ss|sh)es$", "${1}"}, - {"^(m|l)ice$", "${1}ouse"}, - {"(bus)(es)?$", "${1}"}, - {"(o)es$", "${1}"}, - {"(shoe)s$", "${1}"}, - {"(cris|test)(is|es)$", "${1}is"}, - {"^(a)x[ie]s$", "${1}xis"}, - {"(octop|vir)(us|i)$", "${1}us"}, - {"(alias|status)(es)?$", "${1}"}, - {"^(ox)en", "${1}"}, - {"(vert|ind)ices$", "${1}ex"}, - {"(matr)ices$", "${1}ix"}, - {"(quiz)zes$", "${1}"}, - {"(database)s$", "${1}"}, -} - -var irregularInflections = IrregularSlice{ - {"person", "people"}, - {"man", "men"}, - {"child", "children"}, - {"sex", "sexes"}, - {"move", "moves"}, - {"mombie", "mombies"}, -} - -var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police"} - -var compiledPluralMaps []inflection -var compiledSingularMaps []inflection - -func compile() { - compiledPluralMaps = []inflection{} - compiledSingularMaps = []inflection{} - for _, uncountable := range uncountableInflections { - inf := inflection{ - regexp: regexp.MustCompile("^(?i)(" + uncountable + ")$"), - replace: "${1}", - } - compiledPluralMaps = append(compiledPluralMaps, inf) - compiledSingularMaps = append(compiledSingularMaps, inf) - } - - for _, value := range irregularInflections { - infs := []inflection{ - inflection{regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)}, - inflection{regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)}, - inflection{regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural}, - } - compiledPluralMaps = append(compiledPluralMaps, infs...) - } - - for _, value := range irregularInflections { - infs := []inflection{ - inflection{regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)}, - inflection{regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)}, - inflection{regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular}, - } - compiledSingularMaps = append(compiledSingularMaps, infs...) - } - - for i := len(pluralInflections) - 1; i >= 0; i-- { - value := pluralInflections[i] - infs := []inflection{ - inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, - inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, - inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, - } - compiledPluralMaps = append(compiledPluralMaps, infs...) - } - - for i := len(singularInflections) - 1; i >= 0; i-- { - value := singularInflections[i] - infs := []inflection{ - inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, - inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, - inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, - } - compiledSingularMaps = append(compiledSingularMaps, infs...) - } -} - -func init() { - compile() -} - -// AddPlural adds a plural inflection -func AddPlural(find, replace string) { - pluralInflections = append(pluralInflections, Regular{find, replace}) - compile() -} - -// AddSingular adds a singular inflection -func AddSingular(find, replace string) { - singularInflections = append(singularInflections, Regular{find, replace}) - compile() -} - -// AddIrregular adds an irregular inflection -func AddIrregular(singular, plural string) { - irregularInflections = append(irregularInflections, Irregular{singular, plural}) - compile() -} - -// AddUncountable adds an uncountable inflection -func AddUncountable(values ...string) { - uncountableInflections = append(uncountableInflections, values...) - compile() -} - -// GetPlural retrieves the plural inflection values -func GetPlural() RegularSlice { - plurals := make(RegularSlice, len(pluralInflections)) - copy(plurals, pluralInflections) - return plurals -} - -// GetSingular retrieves the singular inflection values -func GetSingular() RegularSlice { - singulars := make(RegularSlice, len(singularInflections)) - copy(singulars, singularInflections) - return singulars -} - -// GetIrregular retrieves the irregular inflection values -func GetIrregular() IrregularSlice { - irregular := make(IrregularSlice, len(irregularInflections)) - copy(irregular, irregularInflections) - return irregular -} - -// GetUncountable retrieves the uncountable inflection values -func GetUncountable() []string { - uncountables := make([]string, len(uncountableInflections)) - copy(uncountables, uncountableInflections) - return uncountables -} - -// SetPlural sets the plural inflections slice -func SetPlural(inflections RegularSlice) { - pluralInflections = inflections - compile() -} - -// SetSingular sets the singular inflections slice -func SetSingular(inflections RegularSlice) { - singularInflections = inflections - compile() -} - -// SetIrregular sets the irregular inflections slice -func SetIrregular(inflections IrregularSlice) { - irregularInflections = inflections - compile() -} - -// SetUncountable sets the uncountable inflections slice -func SetUncountable(inflections []string) { - uncountableInflections = inflections - compile() -} - -// Plural converts a word to its plural form -func Plural(str string) string { - for _, inflection := range compiledPluralMaps { - if inflection.regexp.MatchString(str) { - return inflection.regexp.ReplaceAllString(str, inflection.replace) - } - } - return str -} - -// Singular converts a word to its singular form -func Singular(str string) string { - for _, inflection := range compiledSingularMaps { - if inflection.regexp.MatchString(str) { - return inflection.regexp.ReplaceAllString(str, inflection.replace) - } - } - return str -} diff --git a/vendor/github.com/jinzhu/inflection/wercker.yml b/vendor/github.com/jinzhu/inflection/wercker.yml deleted file mode 100644 index 5e6ce98..0000000 --- a/vendor/github.com/jinzhu/inflection/wercker.yml +++ /dev/null @@ -1,23 +0,0 @@ -box: golang - -build: - steps: - - setup-go-workspace - - # Gets the dependencies - - script: - name: go get - code: | - go get - - # Build the project - - script: - name: go build - code: | - go build ./... - - # Test the project - - script: - name: go test - code: | - go test ./... diff --git a/vendor/github.com/jinzhu/now/Guardfile b/vendor/github.com/jinzhu/now/Guardfile deleted file mode 100644 index 0b860b0..0000000 --- a/vendor/github.com/jinzhu/now/Guardfile +++ /dev/null @@ -1,3 +0,0 @@ -guard 'gotest' do - watch(%r{\.go$}) -end diff --git a/vendor/github.com/jinzhu/now/License b/vendor/github.com/jinzhu/now/License deleted file mode 100644 index 037e165..0000000 --- a/vendor/github.com/jinzhu/now/License +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-NOW Jinzhu - -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. diff --git a/vendor/github.com/jinzhu/now/README.md b/vendor/github.com/jinzhu/now/README.md deleted file mode 100644 index e81d31d..0000000 --- a/vendor/github.com/jinzhu/now/README.md +++ /dev/null @@ -1,137 +0,0 @@ -## Now - -Now is a time toolkit for golang - -[![go report card](https://goreportcard.com/badge/github.com/jinzhu/now "go report card")](https://goreportcard.com/report/github.com/jinzhu/now) -[![test status](https://github.com/jinzhu/now/workflows/tests/badge.svg?branch=master "test status")](https://github.com/jinzhu/now/actions) -[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) - -## Install - -``` -go get -u github.com/jinzhu/now -``` - -## Usage - -Calculating time based on current time - -```go -import "github.com/jinzhu/now" - -time.Now() // 2013-11-18 17:51:49.123456789 Mon - -now.BeginningOfMinute() // 2013-11-18 17:51:00 Mon -now.BeginningOfHour() // 2013-11-18 17:00:00 Mon -now.BeginningOfDay() // 2013-11-18 00:00:00 Mon -now.BeginningOfWeek() // 2013-11-17 00:00:00 Sun -now.BeginningOfMonth() // 2013-11-01 00:00:00 Fri -now.BeginningOfQuarter() // 2013-10-01 00:00:00 Tue -now.BeginningOfYear() // 2013-01-01 00:00:00 Tue - -now.EndOfMinute() // 2013-11-18 17:51:59.999999999 Mon -now.EndOfHour() // 2013-11-18 17:59:59.999999999 Mon -now.EndOfDay() // 2013-11-18 23:59:59.999999999 Mon -now.EndOfWeek() // 2013-11-23 23:59:59.999999999 Sat -now.EndOfMonth() // 2013-11-30 23:59:59.999999999 Sat -now.EndOfQuarter() // 2013-12-31 23:59:59.999999999 Tue -now.EndOfYear() // 2013-12-31 23:59:59.999999999 Tue - -now.WeekStartDay = time.Monday // Set Monday as first day, default is Sunday -now.EndOfWeek() // 2013-11-24 23:59:59.999999999 Sun -``` - -Calculating time based on another time - -```go -t := time.Date(2013, 02, 18, 17, 51, 49, 123456789, time.Now().Location()) -now.With(t).EndOfMonth() // 2013-02-28 23:59:59.999999999 Thu -``` - -Calculating time based on configuration - -```go -location, err := time.LoadLocation("Asia/Shanghai") - -myConfig := &now.Config{ - WeekStartDay: time.Monday, - TimeLocation: location, - TimeFormats: []string{"2006-01-02 15:04:05"}, -} - -t := time.Date(2013, 11, 18, 17, 51, 49, 123456789, time.Now().Location()) // // 2013-11-18 17:51:49.123456789 Mon -myConfig.With(t).BeginningOfWeek() // 2013-11-18 00:00:00 Mon - -myConfig.Parse("2002-10-12 22:14:01") // 2002-10-12 22:14:01 -myConfig.Parse("2002-10-12 22:14") // returns error 'can't parse string as time: 2002-10-12 22:14' -``` - -### Monday/Sunday - -Don't be bothered with the `WeekStartDay` setting, you can use `Monday`, `Sunday` - -```go -now.Monday() // 2013-11-18 00:00:00 Mon -now.Monday("17:44") // 2013-11-18 17:44:00 Mon -now.Sunday() // 2013-11-24 00:00:00 Sun (Next Sunday) -now.Sunday("18:19:24") // 2013-11-24 18:19:24 Sun (Next Sunday) -now.EndOfSunday() // 2013-11-24 23:59:59.999999999 Sun (End of next Sunday) - -t := time.Date(2013, 11, 24, 17, 51, 49, 123456789, time.Now().Location()) // 2013-11-24 17:51:49.123456789 Sun -now.With(t).Monday() // 2013-11-18 00:00:00 Mon (Last Monday if today is Sunday) -now.With(t).Monday("17:44") // 2013-11-18 17:44:00 Mon (Last Monday if today is Sunday) -now.With(t).Sunday() // 2013-11-24 00:00:00 Sun (Beginning Of Today if today is Sunday) -now.With(t).Sunday("18:19:24") // 2013-11-24 18:19:24 Sun (Beginning Of Today if today is Sunday) -now.With(t).EndOfSunday() // 2013-11-24 23:59:59.999999999 Sun (End of Today if today is Sunday) -``` - -### Parse String to Time - -```go -time.Now() // 2013-11-18 17:51:49.123456789 Mon - -// Parse(string) (time.Time, error) -t, err := now.Parse("2017") // 2017-01-01 00:00:00, nil -t, err := now.Parse("2017-10") // 2017-10-01 00:00:00, nil -t, err := now.Parse("2017-10-13") // 2017-10-13 00:00:00, nil -t, err := now.Parse("1999-12-12 12") // 1999-12-12 12:00:00, nil -t, err := now.Parse("1999-12-12 12:20") // 1999-12-12 12:20:00, nil -t, err := now.Parse("1999-12-12 12:20:21") // 1999-12-12 12:20:21, nil -t, err := now.Parse("10-13") // 2013-10-13 00:00:00, nil -t, err := now.Parse("12:20") // 2013-11-18 12:20:00, nil -t, err := now.Parse("12:20:13") // 2013-11-18 12:20:13, nil -t, err := now.Parse("14") // 2013-11-18 14:00:00, nil -t, err := now.Parse("99:99") // 2013-11-18 12:20:00, Can't parse string as time: 99:99 - -// MustParse must parse string to time or it will panic -now.MustParse("2013-01-13") // 2013-01-13 00:00:00 -now.MustParse("02-17") // 2013-02-17 00:00:00 -now.MustParse("2-17") // 2013-02-17 00:00:00 -now.MustParse("8") // 2013-11-18 08:00:00 -now.MustParse("2002-10-12 22:14") // 2002-10-12 22:14:00 -now.MustParse("99:99") // panic: Can't parse string as time: 99:99 -``` - -Extend `now` to support more formats is quite easy, just update `now.TimeFormats` with other time layouts, e.g: - -```go -now.TimeFormats = append(now.TimeFormats, "02 Jan 2006 15:04") -``` - -Please send me pull requests if you want a format to be supported officially - -## Contributing - -You can help to make the project better, check out [http://gorm.io/contribute.html](http://gorm.io/contribute.html) for things you can do. - -# Author - -**jinzhu** - -* -* -* - -## License - -Released under the [MIT License](http://www.opensource.org/licenses/MIT). diff --git a/vendor/github.com/jinzhu/now/main.go b/vendor/github.com/jinzhu/now/main.go deleted file mode 100644 index 8f78bc7..0000000 --- a/vendor/github.com/jinzhu/now/main.go +++ /dev/null @@ -1,200 +0,0 @@ -// Package now is a time toolkit for golang. -// -// More details README here: https://github.com/jinzhu/now -// -// import "github.com/jinzhu/now" -// -// now.BeginningOfMinute() // 2013-11-18 17:51:00 Mon -// now.BeginningOfDay() // 2013-11-18 00:00:00 Mon -// now.EndOfDay() // 2013-11-18 23:59:59.999999999 Mon -package now - -import "time" - -// WeekStartDay set week start day, default is sunday -var WeekStartDay = time.Sunday - -// TimeFormats default time formats will be parsed as -var TimeFormats = []string{ - "2006", "2006-1", "2006-1-2", "2006-1-2 15", "2006-1-2 15:4", "2006-1-2 15:4:5", "1-2", - "15:4:5", "15:4", "15", - "15:4:5 Jan 2, 2006 MST", "2006-01-02 15:04:05.999999999 -0700 MST", "2006-01-02T15:04:05Z0700", "2006-01-02T15:04:05Z07", - "2006.1.2", "2006.1.2 15:04:05", "2006.01.02", "2006.01.02 15:04:05", "2006.01.02 15:04:05.999999999", - "1/2/2006", "1/2/2006 15:4:5", "2006/01/02", "20060102", "2006/01/02 15:04:05", - time.ANSIC, time.UnixDate, time.RubyDate, time.RFC822, time.RFC822Z, time.RFC850, - time.RFC1123, time.RFC1123Z, time.RFC3339, time.RFC3339Nano, - time.Kitchen, time.Stamp, time.StampMilli, time.StampMicro, time.StampNano, -} - -// Config configuration for now package -type Config struct { - WeekStartDay time.Weekday - TimeLocation *time.Location - TimeFormats []string -} - -// DefaultConfig default config -var DefaultConfig *Config - -// New initialize Now based on configuration -func (config *Config) With(t time.Time) *Now { - return &Now{Time: t, Config: config} -} - -// Parse parse string to time based on configuration -func (config *Config) Parse(strs ...string) (time.Time, error) { - if config.TimeLocation == nil { - return config.With(time.Now()).Parse(strs...) - } else { - return config.With(time.Now().In(config.TimeLocation)).Parse(strs...) - } -} - -// MustParse must parse string to time or will panic -func (config *Config) MustParse(strs ...string) time.Time { - if config.TimeLocation == nil { - return config.With(time.Now()).MustParse(strs...) - } else { - return config.With(time.Now().In(config.TimeLocation)).MustParse(strs...) - } -} - -// Now now struct -type Now struct { - time.Time - *Config -} - -// With initialize Now with time -func With(t time.Time) *Now { - config := DefaultConfig - if config == nil { - config = &Config{ - WeekStartDay: WeekStartDay, - TimeFormats: TimeFormats, - } - } - - return &Now{Time: t, Config: config} -} - -// New initialize Now with time -func New(t time.Time) *Now { - return With(t) -} - -// BeginningOfMinute beginning of minute -func BeginningOfMinute() time.Time { - return With(time.Now()).BeginningOfMinute() -} - -// BeginningOfHour beginning of hour -func BeginningOfHour() time.Time { - return With(time.Now()).BeginningOfHour() -} - -// BeginningOfDay beginning of day -func BeginningOfDay() time.Time { - return With(time.Now()).BeginningOfDay() -} - -// BeginningOfWeek beginning of week -func BeginningOfWeek() time.Time { - return With(time.Now()).BeginningOfWeek() -} - -// BeginningOfMonth beginning of month -func BeginningOfMonth() time.Time { - return With(time.Now()).BeginningOfMonth() -} - -// BeginningOfQuarter beginning of quarter -func BeginningOfQuarter() time.Time { - return With(time.Now()).BeginningOfQuarter() -} - -// BeginningOfYear beginning of year -func BeginningOfYear() time.Time { - return With(time.Now()).BeginningOfYear() -} - -// EndOfMinute end of minute -func EndOfMinute() time.Time { - return With(time.Now()).EndOfMinute() -} - -// EndOfHour end of hour -func EndOfHour() time.Time { - return With(time.Now()).EndOfHour() -} - -// EndOfDay end of day -func EndOfDay() time.Time { - return With(time.Now()).EndOfDay() -} - -// EndOfWeek end of week -func EndOfWeek() time.Time { - return With(time.Now()).EndOfWeek() -} - -// EndOfMonth end of month -func EndOfMonth() time.Time { - return With(time.Now()).EndOfMonth() -} - -// EndOfQuarter end of quarter -func EndOfQuarter() time.Time { - return With(time.Now()).EndOfQuarter() -} - -// EndOfYear end of year -func EndOfYear() time.Time { - return With(time.Now()).EndOfYear() -} - -// Monday monday - -func Monday(strs ...string) time.Time { - return With(time.Now()).Monday(strs...) -} - -// Sunday sunday -func Sunday(strs ...string) time.Time { - return With(time.Now()).Sunday(strs...) -} - -// EndOfSunday end of sunday -func EndOfSunday() time.Time { - return With(time.Now()).EndOfSunday() -} - -// Quarter returns the yearly quarter -func Quarter() uint { - return With(time.Now()).Quarter() -} - -// Parse parse string to time -func Parse(strs ...string) (time.Time, error) { - return With(time.Now()).Parse(strs...) -} - -// ParseInLocation parse string to time in location -func ParseInLocation(loc *time.Location, strs ...string) (time.Time, error) { - return With(time.Now().In(loc)).Parse(strs...) -} - -// MustParse must parse string to time or will panic -func MustParse(strs ...string) time.Time { - return With(time.Now()).MustParse(strs...) -} - -// MustParseInLocation must parse string to time in location or will panic -func MustParseInLocation(loc *time.Location, strs ...string) time.Time { - return With(time.Now().In(loc)).MustParse(strs...) -} - -// Between check now between the begin, end time or not -func Between(time1, time2 string) bool { - return With(time.Now()).Between(time1, time2) -} diff --git a/vendor/github.com/jinzhu/now/now.go b/vendor/github.com/jinzhu/now/now.go deleted file mode 100644 index 2f524cc..0000000 --- a/vendor/github.com/jinzhu/now/now.go +++ /dev/null @@ -1,245 +0,0 @@ -package now - -import ( - "errors" - "regexp" - "time" -) - -// BeginningOfMinute beginning of minute -func (now *Now) BeginningOfMinute() time.Time { - return now.Truncate(time.Minute) -} - -// BeginningOfHour beginning of hour -func (now *Now) BeginningOfHour() time.Time { - y, m, d := now.Date() - return time.Date(y, m, d, now.Time.Hour(), 0, 0, 0, now.Time.Location()) -} - -// BeginningOfDay beginning of day -func (now *Now) BeginningOfDay() time.Time { - y, m, d := now.Date() - return time.Date(y, m, d, 0, 0, 0, 0, now.Time.Location()) -} - -// BeginningOfWeek beginning of week -func (now *Now) BeginningOfWeek() time.Time { - t := now.BeginningOfDay() - weekday := int(t.Weekday()) - - if now.WeekStartDay != time.Sunday { - weekStartDayInt := int(now.WeekStartDay) - - if weekday < weekStartDayInt { - weekday = weekday + 7 - weekStartDayInt - } else { - weekday = weekday - weekStartDayInt - } - } - return t.AddDate(0, 0, -weekday) -} - -// BeginningOfMonth beginning of month -func (now *Now) BeginningOfMonth() time.Time { - y, m, _ := now.Date() - return time.Date(y, m, 1, 0, 0, 0, 0, now.Location()) -} - -// BeginningOfQuarter beginning of quarter -func (now *Now) BeginningOfQuarter() time.Time { - month := now.BeginningOfMonth() - offset := (int(month.Month()) - 1) % 3 - return month.AddDate(0, -offset, 0) -} - -// BeginningOfHalf beginning of half year -func (now *Now) BeginningOfHalf() time.Time { - month := now.BeginningOfMonth() - offset := (int(month.Month()) - 1) % 6 - return month.AddDate(0, -offset, 0) -} - -// BeginningOfYear BeginningOfYear beginning of year -func (now *Now) BeginningOfYear() time.Time { - y, _, _ := now.Date() - return time.Date(y, time.January, 1, 0, 0, 0, 0, now.Location()) -} - -// EndOfMinute end of minute -func (now *Now) EndOfMinute() time.Time { - return now.BeginningOfMinute().Add(time.Minute - time.Nanosecond) -} - -// EndOfHour end of hour -func (now *Now) EndOfHour() time.Time { - return now.BeginningOfHour().Add(time.Hour - time.Nanosecond) -} - -// EndOfDay end of day -func (now *Now) EndOfDay() time.Time { - y, m, d := now.Date() - return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), now.Location()) -} - -// EndOfWeek end of week -func (now *Now) EndOfWeek() time.Time { - return now.BeginningOfWeek().AddDate(0, 0, 7).Add(-time.Nanosecond) -} - -// EndOfMonth end of month -func (now *Now) EndOfMonth() time.Time { - return now.BeginningOfMonth().AddDate(0, 1, 0).Add(-time.Nanosecond) -} - -// EndOfQuarter end of quarter -func (now *Now) EndOfQuarter() time.Time { - return now.BeginningOfQuarter().AddDate(0, 3, 0).Add(-time.Nanosecond) -} - -// EndOfHalf end of half year -func (now *Now) EndOfHalf() time.Time { - return now.BeginningOfHalf().AddDate(0, 6, 0).Add(-time.Nanosecond) -} - -// EndOfYear end of year -func (now *Now) EndOfYear() time.Time { - return now.BeginningOfYear().AddDate(1, 0, 0).Add(-time.Nanosecond) -} - -// Monday monday -/* -func (now *Now) Monday() time.Time { - t := now.BeginningOfDay() - weekday := int(t.Weekday()) - if weekday == 0 { - weekday = 7 - } - return t.AddDate(0, 0, -weekday+1) -} -*/ - -func (now *Now) Monday(strs ...string) time.Time { - var parseTime time.Time - var err error - if len(strs) > 0 { - parseTime, err = now.Parse(strs...) - if err != nil { - panic(err) - } - } else { - parseTime = now.BeginningOfDay() - } - weekday := int(parseTime.Weekday()) - if weekday == 0 { - weekday = 7 - } - return parseTime.AddDate(0, 0, -weekday+1) -} - -func (now *Now) Sunday(strs ...string) time.Time { - var parseTime time.Time - var err error - if len(strs) > 0 { - parseTime, err = now.Parse(strs...) - if err != nil { - panic(err) - } - } else { - parseTime = now.BeginningOfDay() - } - weekday := int(parseTime.Weekday()) - if weekday == 0 { - weekday = 7 - } - return parseTime.AddDate(0, 0, (7 - weekday)) -} - -// EndOfSunday end of sunday -func (now *Now) EndOfSunday() time.Time { - return New(now.Sunday()).EndOfDay() -} - -// Quarter returns the yearly quarter -func (now *Now) Quarter() uint { - return (uint(now.Month())-1)/3 + 1 -} - -func (now *Now) parseWithFormat(str string, location *time.Location) (t time.Time, err error) { - for _, format := range now.TimeFormats { - t, err = time.ParseInLocation(format, str, location) - - if err == nil { - return - } - } - err = errors.New("Can't parse string as time: " + str) - return -} - -var hasTimeRegexp = regexp.MustCompile(`(\s+|^\s*|T)\d{1,2}((:\d{1,2})*|((:\d{1,2}){2}\.(\d{3}|\d{6}|\d{9})))(\s*$|[Z+-])`) // match 15:04:05, 15:04:05.000, 15:04:05.000000 15, 2017-01-01 15:04, 2021-07-20T00:59:10Z, 2021-07-20T00:59:10+08:00, 2021-07-20T00:00:10-07:00 etc -var onlyTimeRegexp = regexp.MustCompile(`^\s*\d{1,2}((:\d{1,2})*|((:\d{1,2}){2}\.(\d{3}|\d{6}|\d{9})))\s*$`) // match 15:04:05, 15, 15:04:05.000, 15:04:05.000000, etc - -// Parse parse string to time -func (now *Now) Parse(strs ...string) (t time.Time, err error) { - var ( - setCurrentTime bool - parseTime []int - currentLocation = now.Location() - onlyTimeInStr = true - currentTime = formatTimeToList(now.Time) - ) - - for _, str := range strs { - hasTimeInStr := hasTimeRegexp.MatchString(str) // match 15:04:05, 15 - onlyTimeInStr = hasTimeInStr && onlyTimeInStr && onlyTimeRegexp.MatchString(str) - if t, err = now.parseWithFormat(str, currentLocation); err == nil { - location := t.Location() - parseTime = formatTimeToList(t) - - for i, v := range parseTime { - // Don't reset hour, minute, second if current time str including time - if hasTimeInStr && i <= 3 { - continue - } - - // If value is zero, replace it with current time - if v == 0 { - if setCurrentTime { - parseTime[i] = currentTime[i] - } - } else { - setCurrentTime = true - } - - // if current time only includes time, should change day, month to current time - if onlyTimeInStr { - if i == 4 || i == 5 { - parseTime[i] = currentTime[i] - continue - } - } - } - - t = time.Date(parseTime[6], time.Month(parseTime[5]), parseTime[4], parseTime[3], parseTime[2], parseTime[1], parseTime[0], location) - currentTime = formatTimeToList(t) - } - } - return -} - -// MustParse must parse string to time or it will panic -func (now *Now) MustParse(strs ...string) (t time.Time) { - t, err := now.Parse(strs...) - if err != nil { - panic(err) - } - return t -} - -// Between check time between the begin, end time or not -func (now *Now) Between(begin, end string) bool { - beginTime := now.MustParse(begin) - endTime := now.MustParse(end) - return now.After(beginTime) && now.Before(endTime) -} diff --git a/vendor/github.com/jinzhu/now/time.go b/vendor/github.com/jinzhu/now/time.go deleted file mode 100644 index 52dd8b2..0000000 --- a/vendor/github.com/jinzhu/now/time.go +++ /dev/null @@ -1,9 +0,0 @@ -package now - -import "time" - -func formatTimeToList(t time.Time) []int { - hour, min, sec := t.Clock() - year, month, day := t.Date() - return []int{t.Nanosecond(), sec, min, hour, day, int(month), year} -} diff --git a/vendor/github.com/json-iterator/go/.codecov.yml b/vendor/github.com/json-iterator/go/.codecov.yml deleted file mode 100644 index 955dc0b..0000000 --- a/vendor/github.com/json-iterator/go/.codecov.yml +++ /dev/null @@ -1,3 +0,0 @@ -ignore: - - "output_tests/.*" - diff --git a/vendor/github.com/json-iterator/go/.gitignore b/vendor/github.com/json-iterator/go/.gitignore deleted file mode 100644 index 1555653..0000000 --- a/vendor/github.com/json-iterator/go/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/vendor -/bug_test.go -/coverage.txt -/.idea diff --git a/vendor/github.com/json-iterator/go/.travis.yml b/vendor/github.com/json-iterator/go/.travis.yml deleted file mode 100644 index 449e67c..0000000 --- a/vendor/github.com/json-iterator/go/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go - -go: - - 1.8.x - - 1.x - -before_install: - - go get -t -v ./... - -script: - - ./test.sh - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/json-iterator/go/Gopkg.lock b/vendor/github.com/json-iterator/go/Gopkg.lock deleted file mode 100644 index c8a9fbb..0000000 --- a/vendor/github.com/json-iterator/go/Gopkg.lock +++ /dev/null @@ -1,21 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/modern-go/concurrent" - packages = ["."] - revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a" - version = "1.0.0" - -[[projects]] - name = "github.com/modern-go/reflect2" - packages = ["."] - revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" - version = "1.0.1" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "ea54a775e5a354cb015502d2e7aa4b74230fc77e894f34a838b268c25ec8eeb8" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/github.com/json-iterator/go/Gopkg.toml b/vendor/github.com/json-iterator/go/Gopkg.toml deleted file mode 100644 index 313a0f8..0000000 --- a/vendor/github.com/json-iterator/go/Gopkg.toml +++ /dev/null @@ -1,26 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" - -ignored = ["github.com/davecgh/go-spew*","github.com/google/gofuzz*","github.com/stretchr/testify*"] - -[[constraint]] - name = "github.com/modern-go/reflect2" - version = "1.0.1" diff --git a/vendor/github.com/json-iterator/go/LICENSE b/vendor/github.com/json-iterator/go/LICENSE deleted file mode 100644 index 2cf4f5a..0000000 --- a/vendor/github.com/json-iterator/go/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 json-iterator - -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. diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md deleted file mode 100644 index 52b111d..0000000 --- a/vendor/github.com/json-iterator/go/README.md +++ /dev/null @@ -1,87 +0,0 @@ -[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) -[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/json-iterator/go) -[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) -[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) -[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) -[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE) -[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) - -A high-performance 100% compatible drop-in replacement of "encoding/json" - -You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go) - -# Benchmark - -![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) - -Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go - -Raw Result (easyjson requires static code generation) - -| | ns/op | allocation bytes | allocation times | -| --------------- | ----------- | ---------------- | ---------------- | -| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | -| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | -| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | -| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | -| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | -| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | - -Always benchmark with your own workload. -The result depends heavily on the data input. - -# Usage - -100% compatibility with standard lib - -Replace - -```go -import "encoding/json" -json.Marshal(&data) -``` - -with - -```go -import jsoniter "github.com/json-iterator/go" - -var json = jsoniter.ConfigCompatibleWithStandardLibrary -json.Marshal(&data) -``` - -Replace - -```go -import "encoding/json" -json.Unmarshal(input, &data) -``` - -with - -```go -import jsoniter "github.com/json-iterator/go" - -var json = jsoniter.ConfigCompatibleWithStandardLibrary -json.Unmarshal(input, &data) -``` - -[More documentation](http://jsoniter.com/migrate-from-go-std.html) - -# How to get - -``` -go get github.com/json-iterator/go -``` - -# Contribution Welcomed ! - -Contributors - -- [thockin](https://github.com/thockin) -- [mattn](https://github.com/mattn) -- [cch123](https://github.com/cch123) -- [Oleg Shaldybin](https://github.com/olegshaldybin) -- [Jason Toffaletti](https://github.com/toffaletti) - -Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) diff --git a/vendor/github.com/json-iterator/go/adapter.go b/vendor/github.com/json-iterator/go/adapter.go deleted file mode 100644 index 92d2cc4..0000000 --- a/vendor/github.com/json-iterator/go/adapter.go +++ /dev/null @@ -1,150 +0,0 @@ -package jsoniter - -import ( - "bytes" - "io" -) - -// RawMessage to make replace json with jsoniter -type RawMessage []byte - -// Unmarshal adapts to json/encoding Unmarshal API -// -// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. -// Refer to https://godoc.org/encoding/json#Unmarshal for more information -func Unmarshal(data []byte, v interface{}) error { - return ConfigDefault.Unmarshal(data, v) -} - -// UnmarshalFromString is a convenient method to read from string instead of []byte -func UnmarshalFromString(str string, v interface{}) error { - return ConfigDefault.UnmarshalFromString(str, v) -} - -// Get quick method to get value from deeply nested JSON structure -func Get(data []byte, path ...interface{}) Any { - return ConfigDefault.Get(data, path...) -} - -// Marshal adapts to json/encoding Marshal API -// -// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API -// Refer to https://godoc.org/encoding/json#Marshal for more information -func Marshal(v interface{}) ([]byte, error) { - return ConfigDefault.Marshal(v) -} - -// MarshalIndent same as json.MarshalIndent. Prefix is not supported. -func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - return ConfigDefault.MarshalIndent(v, prefix, indent) -} - -// MarshalToString convenient method to write as string instead of []byte -func MarshalToString(v interface{}) (string, error) { - return ConfigDefault.MarshalToString(v) -} - -// NewDecoder adapts to json/stream NewDecoder API. -// -// NewDecoder returns a new decoder that reads from r. -// -// Instead of a json/encoding Decoder, an Decoder is returned -// Refer to https://godoc.org/encoding/json#NewDecoder for more information -func NewDecoder(reader io.Reader) *Decoder { - return ConfigDefault.NewDecoder(reader) -} - -// Decoder reads and decodes JSON values from an input stream. -// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress) -type Decoder struct { - iter *Iterator -} - -// Decode decode JSON into interface{} -func (adapter *Decoder) Decode(obj interface{}) error { - if adapter.iter.head == adapter.iter.tail && adapter.iter.reader != nil { - if !adapter.iter.loadMore() { - return io.EOF - } - } - adapter.iter.ReadVal(obj) - err := adapter.iter.Error - if err == io.EOF { - return nil - } - return adapter.iter.Error -} - -// More is there more? -func (adapter *Decoder) More() bool { - iter := adapter.iter - if iter.Error != nil { - return false - } - c := iter.nextToken() - if c == 0 { - return false - } - iter.unreadByte() - return c != ']' && c != '}' -} - -// Buffered remaining buffer -func (adapter *Decoder) Buffered() io.Reader { - remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail] - return bytes.NewReader(remaining) -} - -// UseNumber causes the Decoder to unmarshal a number into an interface{} as a -// Number instead of as a float64. -func (adapter *Decoder) UseNumber() { - cfg := adapter.iter.cfg.configBeforeFrozen - cfg.UseNumber = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) -} - -// DisallowUnknownFields causes the Decoder to return an error when the destination -// is a struct and the input contains object keys which do not match any -// non-ignored, exported fields in the destination. -func (adapter *Decoder) DisallowUnknownFields() { - cfg := adapter.iter.cfg.configBeforeFrozen - cfg.DisallowUnknownFields = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) -} - -// NewEncoder same as json.NewEncoder -func NewEncoder(writer io.Writer) *Encoder { - return ConfigDefault.NewEncoder(writer) -} - -// Encoder same as json.Encoder -type Encoder struct { - stream *Stream -} - -// Encode encode interface{} as JSON to io.Writer -func (adapter *Encoder) Encode(val interface{}) error { - adapter.stream.WriteVal(val) - adapter.stream.WriteRaw("\n") - adapter.stream.Flush() - return adapter.stream.Error -} - -// SetIndent set the indention. Prefix is not supported -func (adapter *Encoder) SetIndent(prefix, indent string) { - config := adapter.stream.cfg.configBeforeFrozen - config.IndentionStep = len(indent) - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) -} - -// SetEscapeHTML escape html by default, set to false to disable -func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { - config := adapter.stream.cfg.configBeforeFrozen - config.EscapeHTML = escapeHTML - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) -} - -// Valid reports whether data is a valid JSON encoding. -func Valid(data []byte) bool { - return ConfigDefault.Valid(data) -} diff --git a/vendor/github.com/json-iterator/go/any.go b/vendor/github.com/json-iterator/go/any.go deleted file mode 100644 index f6b8aea..0000000 --- a/vendor/github.com/json-iterator/go/any.go +++ /dev/null @@ -1,325 +0,0 @@ -package jsoniter - -import ( - "errors" - "fmt" - "github.com/modern-go/reflect2" - "io" - "reflect" - "strconv" - "unsafe" -) - -// Any generic object representation. -// The lazy json implementation holds []byte and parse lazily. -type Any interface { - LastError() error - ValueType() ValueType - MustBeValid() Any - ToBool() bool - ToInt() int - ToInt32() int32 - ToInt64() int64 - ToUint() uint - ToUint32() uint32 - ToUint64() uint64 - ToFloat32() float32 - ToFloat64() float64 - ToString() string - ToVal(val interface{}) - Get(path ...interface{}) Any - Size() int - Keys() []string - GetInterface() interface{} - WriteTo(stream *Stream) -} - -type baseAny struct{} - -func (any *baseAny) Get(path ...interface{}) Any { - return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} -} - -func (any *baseAny) Size() int { - return 0 -} - -func (any *baseAny) Keys() []string { - return []string{} -} - -func (any *baseAny) ToVal(obj interface{}) { - panic("not implemented") -} - -// WrapInt32 turn int32 into Any interface -func WrapInt32(val int32) Any { - return &int32Any{baseAny{}, val} -} - -// WrapInt64 turn int64 into Any interface -func WrapInt64(val int64) Any { - return &int64Any{baseAny{}, val} -} - -// WrapUint32 turn uint32 into Any interface -func WrapUint32(val uint32) Any { - return &uint32Any{baseAny{}, val} -} - -// WrapUint64 turn uint64 into Any interface -func WrapUint64(val uint64) Any { - return &uint64Any{baseAny{}, val} -} - -// WrapFloat64 turn float64 into Any interface -func WrapFloat64(val float64) Any { - return &floatAny{baseAny{}, val} -} - -// WrapString turn string into Any interface -func WrapString(val string) Any { - return &stringAny{baseAny{}, val} -} - -// Wrap turn a go object into Any interface -func Wrap(val interface{}) Any { - if val == nil { - return &nilAny{} - } - asAny, isAny := val.(Any) - if isAny { - return asAny - } - typ := reflect2.TypeOf(val) - switch typ.Kind() { - case reflect.Slice: - return wrapArray(val) - case reflect.Struct: - return wrapStruct(val) - case reflect.Map: - return wrapMap(val) - case reflect.String: - return WrapString(val.(string)) - case reflect.Int: - if strconv.IntSize == 32 { - return WrapInt32(int32(val.(int))) - } - return WrapInt64(int64(val.(int))) - case reflect.Int8: - return WrapInt32(int32(val.(int8))) - case reflect.Int16: - return WrapInt32(int32(val.(int16))) - case reflect.Int32: - return WrapInt32(val.(int32)) - case reflect.Int64: - return WrapInt64(val.(int64)) - case reflect.Uint: - if strconv.IntSize == 32 { - return WrapUint32(uint32(val.(uint))) - } - return WrapUint64(uint64(val.(uint))) - case reflect.Uintptr: - if ptrSize == 32 { - return WrapUint32(uint32(val.(uintptr))) - } - return WrapUint64(uint64(val.(uintptr))) - case reflect.Uint8: - return WrapUint32(uint32(val.(uint8))) - case reflect.Uint16: - return WrapUint32(uint32(val.(uint16))) - case reflect.Uint32: - return WrapUint32(uint32(val.(uint32))) - case reflect.Uint64: - return WrapUint64(val.(uint64)) - case reflect.Float32: - return WrapFloat64(float64(val.(float32))) - case reflect.Float64: - return WrapFloat64(val.(float64)) - case reflect.Bool: - if val.(bool) == true { - return &trueAny{} - } - return &falseAny{} - } - return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)} -} - -// ReadAny read next JSON element as an Any object. It is a better json.RawMessage. -func (iter *Iterator) ReadAny() Any { - return iter.readAny() -} - -func (iter *Iterator) readAny() Any { - c := iter.nextToken() - switch c { - case '"': - iter.unreadByte() - return &stringAny{baseAny{}, iter.ReadString()} - case 'n': - iter.skipThreeBytes('u', 'l', 'l') // null - return &nilAny{} - case 't': - iter.skipThreeBytes('r', 'u', 'e') // true - return &trueAny{} - case 'f': - iter.skipFourBytes('a', 'l', 's', 'e') // false - return &falseAny{} - case '{': - return iter.readObjectAny() - case '[': - return iter.readArrayAny() - case '-': - return iter.readNumberAny(false) - case 0: - return &invalidAny{baseAny{}, errors.New("input is empty")} - default: - return iter.readNumberAny(true) - } -} - -func (iter *Iterator) readNumberAny(positive bool) Any { - iter.startCapture(iter.head - 1) - iter.skipNumber() - lazyBuf := iter.stopCapture() - return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} -} - -func (iter *Iterator) readObjectAny() Any { - iter.startCapture(iter.head - 1) - iter.skipObject() - lazyBuf := iter.stopCapture() - return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} -} - -func (iter *Iterator) readArrayAny() Any { - iter.startCapture(iter.head - 1) - iter.skipArray() - lazyBuf := iter.stopCapture() - return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} -} - -func locateObjectField(iter *Iterator, target string) []byte { - var found []byte - iter.ReadObjectCB(func(iter *Iterator, field string) bool { - if field == target { - found = iter.SkipAndReturnBytes() - return false - } - iter.Skip() - return true - }) - return found -} - -func locateArrayElement(iter *Iterator, target int) []byte { - var found []byte - n := 0 - iter.ReadArrayCB(func(iter *Iterator) bool { - if n == target { - found = iter.SkipAndReturnBytes() - return false - } - iter.Skip() - n++ - return true - }) - return found -} - -func locatePath(iter *Iterator, path []interface{}) Any { - for i, pathKeyObj := range path { - switch pathKey := pathKeyObj.(type) { - case string: - valueBytes := locateObjectField(iter, pathKey) - if valueBytes == nil { - return newInvalidAny(path[i:]) - } - iter.ResetBytes(valueBytes) - case int: - valueBytes := locateArrayElement(iter, pathKey) - if valueBytes == nil { - return newInvalidAny(path[i:]) - } - iter.ResetBytes(valueBytes) - case int32: - if '*' == pathKey { - return iter.readAny().Get(path[i:]...) - } - return newInvalidAny(path[i:]) - default: - return newInvalidAny(path[i:]) - } - } - if iter.Error != nil && iter.Error != io.EOF { - return &invalidAny{baseAny{}, iter.Error} - } - return iter.readAny() -} - -var anyType = reflect2.TypeOfPtr((*Any)(nil)).Elem() - -func createDecoderOfAny(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ == anyType { - return &directAnyCodec{} - } - if typ.Implements(anyType) { - return &anyCodec{ - valType: typ, - } - } - return nil -} - -func createEncoderOfAny(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ == anyType { - return &directAnyCodec{} - } - if typ.Implements(anyType) { - return &anyCodec{ - valType: typ, - } - } - return nil -} - -type anyCodec struct { - valType reflect2.Type -} - -func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - panic("not implemented") -} - -func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := codec.valType.UnsafeIndirect(ptr) - any := obj.(Any) - any.WriteTo(stream) -} - -func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool { - obj := codec.valType.UnsafeIndirect(ptr) - any := obj.(Any) - return any.Size() == 0 -} - -type directAnyCodec struct { -} - -func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - *(*Any)(ptr) = iter.readAny() -} - -func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - any := *(*Any)(ptr) - if any == nil { - stream.WriteNil() - return - } - any.WriteTo(stream) -} - -func (codec *directAnyCodec) IsEmpty(ptr unsafe.Pointer) bool { - any := *(*Any)(ptr) - return any.Size() == 0 -} diff --git a/vendor/github.com/json-iterator/go/any_array.go b/vendor/github.com/json-iterator/go/any_array.go deleted file mode 100644 index 0449e9a..0000000 --- a/vendor/github.com/json-iterator/go/any_array.go +++ /dev/null @@ -1,278 +0,0 @@ -package jsoniter - -import ( - "reflect" - "unsafe" -) - -type arrayLazyAny struct { - baseAny - cfg *frozenConfig - buf []byte - err error -} - -func (any *arrayLazyAny) ValueType() ValueType { - return ArrayValue -} - -func (any *arrayLazyAny) MustBeValid() Any { - return any -} - -func (any *arrayLazyAny) LastError() error { - return any.err -} - -func (any *arrayLazyAny) ToBool() bool { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.ReadArray() -} - -func (any *arrayLazyAny) ToInt() int { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToInt32() int32 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToInt64() int64 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToUint() uint { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToUint32() uint32 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToUint64() uint64 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToFloat32() float32 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToFloat64() float64 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToString() string { - return *(*string)(unsafe.Pointer(&any.buf)) -} - -func (any *arrayLazyAny) ToVal(val interface{}) { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadVal(val) -} - -func (any *arrayLazyAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case int: - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - valueBytes := locateArrayElement(iter, firstPath) - if valueBytes == nil { - return newInvalidAny(path) - } - iter.ResetBytes(valueBytes) - return locatePath(iter, path[1:]) - case int32: - if '*' == firstPath { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - arr := make([]Any, 0) - iter.ReadArrayCB(func(iter *Iterator) bool { - found := iter.readAny().Get(path[1:]...) - if found.ValueType() != InvalidValue { - arr = append(arr, found) - } - return true - }) - return wrapArray(arr) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *arrayLazyAny) Size() int { - size := 0 - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadArrayCB(func(iter *Iterator) bool { - size++ - iter.Skip() - return true - }) - return size -} - -func (any *arrayLazyAny) WriteTo(stream *Stream) { - stream.Write(any.buf) -} - -func (any *arrayLazyAny) GetInterface() interface{} { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.Read() -} - -type arrayAny struct { - baseAny - val reflect.Value -} - -func wrapArray(val interface{}) *arrayAny { - return &arrayAny{baseAny{}, reflect.ValueOf(val)} -} - -func (any *arrayAny) ValueType() ValueType { - return ArrayValue -} - -func (any *arrayAny) MustBeValid() Any { - return any -} - -func (any *arrayAny) LastError() error { - return nil -} - -func (any *arrayAny) ToBool() bool { - return any.val.Len() != 0 -} - -func (any *arrayAny) ToInt() int { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToInt32() int32 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToInt64() int64 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToUint() uint { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToUint32() uint32 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToUint64() uint64 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToFloat32() float32 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToFloat64() float64 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToString() string { - str, _ := MarshalToString(any.val.Interface()) - return str -} - -func (any *arrayAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case int: - if firstPath < 0 || firstPath >= any.val.Len() { - return newInvalidAny(path) - } - return Wrap(any.val.Index(firstPath).Interface()) - case int32: - if '*' == firstPath { - mappedAll := make([]Any, 0) - for i := 0; i < any.val.Len(); i++ { - mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) - if mapped.ValueType() != InvalidValue { - mappedAll = append(mappedAll, mapped) - } - } - return wrapArray(mappedAll) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *arrayAny) Size() int { - return any.val.Len() -} - -func (any *arrayAny) WriteTo(stream *Stream) { - stream.WriteVal(any.val) -} - -func (any *arrayAny) GetInterface() interface{} { - return any.val.Interface() -} diff --git a/vendor/github.com/json-iterator/go/any_bool.go b/vendor/github.com/json-iterator/go/any_bool.go deleted file mode 100644 index 9452324..0000000 --- a/vendor/github.com/json-iterator/go/any_bool.go +++ /dev/null @@ -1,137 +0,0 @@ -package jsoniter - -type trueAny struct { - baseAny -} - -func (any *trueAny) LastError() error { - return nil -} - -func (any *trueAny) ToBool() bool { - return true -} - -func (any *trueAny) ToInt() int { - return 1 -} - -func (any *trueAny) ToInt32() int32 { - return 1 -} - -func (any *trueAny) ToInt64() int64 { - return 1 -} - -func (any *trueAny) ToUint() uint { - return 1 -} - -func (any *trueAny) ToUint32() uint32 { - return 1 -} - -func (any *trueAny) ToUint64() uint64 { - return 1 -} - -func (any *trueAny) ToFloat32() float32 { - return 1 -} - -func (any *trueAny) ToFloat64() float64 { - return 1 -} - -func (any *trueAny) ToString() string { - return "true" -} - -func (any *trueAny) WriteTo(stream *Stream) { - stream.WriteTrue() -} - -func (any *trueAny) Parse() *Iterator { - return nil -} - -func (any *trueAny) GetInterface() interface{} { - return true -} - -func (any *trueAny) ValueType() ValueType { - return BoolValue -} - -func (any *trueAny) MustBeValid() Any { - return any -} - -type falseAny struct { - baseAny -} - -func (any *falseAny) LastError() error { - return nil -} - -func (any *falseAny) ToBool() bool { - return false -} - -func (any *falseAny) ToInt() int { - return 0 -} - -func (any *falseAny) ToInt32() int32 { - return 0 -} - -func (any *falseAny) ToInt64() int64 { - return 0 -} - -func (any *falseAny) ToUint() uint { - return 0 -} - -func (any *falseAny) ToUint32() uint32 { - return 0 -} - -func (any *falseAny) ToUint64() uint64 { - return 0 -} - -func (any *falseAny) ToFloat32() float32 { - return 0 -} - -func (any *falseAny) ToFloat64() float64 { - return 0 -} - -func (any *falseAny) ToString() string { - return "false" -} - -func (any *falseAny) WriteTo(stream *Stream) { - stream.WriteFalse() -} - -func (any *falseAny) Parse() *Iterator { - return nil -} - -func (any *falseAny) GetInterface() interface{} { - return false -} - -func (any *falseAny) ValueType() ValueType { - return BoolValue -} - -func (any *falseAny) MustBeValid() Any { - return any -} diff --git a/vendor/github.com/json-iterator/go/any_float.go b/vendor/github.com/json-iterator/go/any_float.go deleted file mode 100644 index 35fdb09..0000000 --- a/vendor/github.com/json-iterator/go/any_float.go +++ /dev/null @@ -1,83 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type floatAny struct { - baseAny - val float64 -} - -func (any *floatAny) Parse() *Iterator { - return nil -} - -func (any *floatAny) ValueType() ValueType { - return NumberValue -} - -func (any *floatAny) MustBeValid() Any { - return any -} - -func (any *floatAny) LastError() error { - return nil -} - -func (any *floatAny) ToBool() bool { - return any.ToFloat64() != 0 -} - -func (any *floatAny) ToInt() int { - return int(any.val) -} - -func (any *floatAny) ToInt32() int32 { - return int32(any.val) -} - -func (any *floatAny) ToInt64() int64 { - return int64(any.val) -} - -func (any *floatAny) ToUint() uint { - if any.val > 0 { - return uint(any.val) - } - return 0 -} - -func (any *floatAny) ToUint32() uint32 { - if any.val > 0 { - return uint32(any.val) - } - return 0 -} - -func (any *floatAny) ToUint64() uint64 { - if any.val > 0 { - return uint64(any.val) - } - return 0 -} - -func (any *floatAny) ToFloat32() float32 { - return float32(any.val) -} - -func (any *floatAny) ToFloat64() float64 { - return any.val -} - -func (any *floatAny) ToString() string { - return strconv.FormatFloat(any.val, 'E', -1, 64) -} - -func (any *floatAny) WriteTo(stream *Stream) { - stream.WriteFloat64(any.val) -} - -func (any *floatAny) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_int32.go b/vendor/github.com/json-iterator/go/any_int32.go deleted file mode 100644 index 1b56f39..0000000 --- a/vendor/github.com/json-iterator/go/any_int32.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type int32Any struct { - baseAny - val int32 -} - -func (any *int32Any) LastError() error { - return nil -} - -func (any *int32Any) ValueType() ValueType { - return NumberValue -} - -func (any *int32Any) MustBeValid() Any { - return any -} - -func (any *int32Any) ToBool() bool { - return any.val != 0 -} - -func (any *int32Any) ToInt() int { - return int(any.val) -} - -func (any *int32Any) ToInt32() int32 { - return any.val -} - -func (any *int32Any) ToInt64() int64 { - return int64(any.val) -} - -func (any *int32Any) ToUint() uint { - return uint(any.val) -} - -func (any *int32Any) ToUint32() uint32 { - return uint32(any.val) -} - -func (any *int32Any) ToUint64() uint64 { - return uint64(any.val) -} - -func (any *int32Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *int32Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *int32Any) ToString() string { - return strconv.FormatInt(int64(any.val), 10) -} - -func (any *int32Any) WriteTo(stream *Stream) { - stream.WriteInt32(any.val) -} - -func (any *int32Any) Parse() *Iterator { - return nil -} - -func (any *int32Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_int64.go b/vendor/github.com/json-iterator/go/any_int64.go deleted file mode 100644 index c440d72..0000000 --- a/vendor/github.com/json-iterator/go/any_int64.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type int64Any struct { - baseAny - val int64 -} - -func (any *int64Any) LastError() error { - return nil -} - -func (any *int64Any) ValueType() ValueType { - return NumberValue -} - -func (any *int64Any) MustBeValid() Any { - return any -} - -func (any *int64Any) ToBool() bool { - return any.val != 0 -} - -func (any *int64Any) ToInt() int { - return int(any.val) -} - -func (any *int64Any) ToInt32() int32 { - return int32(any.val) -} - -func (any *int64Any) ToInt64() int64 { - return any.val -} - -func (any *int64Any) ToUint() uint { - return uint(any.val) -} - -func (any *int64Any) ToUint32() uint32 { - return uint32(any.val) -} - -func (any *int64Any) ToUint64() uint64 { - return uint64(any.val) -} - -func (any *int64Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *int64Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *int64Any) ToString() string { - return strconv.FormatInt(any.val, 10) -} - -func (any *int64Any) WriteTo(stream *Stream) { - stream.WriteInt64(any.val) -} - -func (any *int64Any) Parse() *Iterator { - return nil -} - -func (any *int64Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_invalid.go b/vendor/github.com/json-iterator/go/any_invalid.go deleted file mode 100644 index 1d859ea..0000000 --- a/vendor/github.com/json-iterator/go/any_invalid.go +++ /dev/null @@ -1,82 +0,0 @@ -package jsoniter - -import "fmt" - -type invalidAny struct { - baseAny - err error -} - -func newInvalidAny(path []interface{}) *invalidAny { - return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)} -} - -func (any *invalidAny) LastError() error { - return any.err -} - -func (any *invalidAny) ValueType() ValueType { - return InvalidValue -} - -func (any *invalidAny) MustBeValid() Any { - panic(any.err) -} - -func (any *invalidAny) ToBool() bool { - return false -} - -func (any *invalidAny) ToInt() int { - return 0 -} - -func (any *invalidAny) ToInt32() int32 { - return 0 -} - -func (any *invalidAny) ToInt64() int64 { - return 0 -} - -func (any *invalidAny) ToUint() uint { - return 0 -} - -func (any *invalidAny) ToUint32() uint32 { - return 0 -} - -func (any *invalidAny) ToUint64() uint64 { - return 0 -} - -func (any *invalidAny) ToFloat32() float32 { - return 0 -} - -func (any *invalidAny) ToFloat64() float64 { - return 0 -} - -func (any *invalidAny) ToString() string { - return "" -} - -func (any *invalidAny) WriteTo(stream *Stream) { -} - -func (any *invalidAny) Get(path ...interface{}) Any { - if any.err == nil { - return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)} - } - return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)} -} - -func (any *invalidAny) Parse() *Iterator { - return nil -} - -func (any *invalidAny) GetInterface() interface{} { - return nil -} diff --git a/vendor/github.com/json-iterator/go/any_nil.go b/vendor/github.com/json-iterator/go/any_nil.go deleted file mode 100644 index d04cb54..0000000 --- a/vendor/github.com/json-iterator/go/any_nil.go +++ /dev/null @@ -1,69 +0,0 @@ -package jsoniter - -type nilAny struct { - baseAny -} - -func (any *nilAny) LastError() error { - return nil -} - -func (any *nilAny) ValueType() ValueType { - return NilValue -} - -func (any *nilAny) MustBeValid() Any { - return any -} - -func (any *nilAny) ToBool() bool { - return false -} - -func (any *nilAny) ToInt() int { - return 0 -} - -func (any *nilAny) ToInt32() int32 { - return 0 -} - -func (any *nilAny) ToInt64() int64 { - return 0 -} - -func (any *nilAny) ToUint() uint { - return 0 -} - -func (any *nilAny) ToUint32() uint32 { - return 0 -} - -func (any *nilAny) ToUint64() uint64 { - return 0 -} - -func (any *nilAny) ToFloat32() float32 { - return 0 -} - -func (any *nilAny) ToFloat64() float64 { - return 0 -} - -func (any *nilAny) ToString() string { - return "" -} - -func (any *nilAny) WriteTo(stream *Stream) { - stream.WriteNil() -} - -func (any *nilAny) Parse() *Iterator { - return nil -} - -func (any *nilAny) GetInterface() interface{} { - return nil -} diff --git a/vendor/github.com/json-iterator/go/any_number.go b/vendor/github.com/json-iterator/go/any_number.go deleted file mode 100644 index 9d1e901..0000000 --- a/vendor/github.com/json-iterator/go/any_number.go +++ /dev/null @@ -1,123 +0,0 @@ -package jsoniter - -import ( - "io" - "unsafe" -) - -type numberLazyAny struct { - baseAny - cfg *frozenConfig - buf []byte - err error -} - -func (any *numberLazyAny) ValueType() ValueType { - return NumberValue -} - -func (any *numberLazyAny) MustBeValid() Any { - return any -} - -func (any *numberLazyAny) LastError() error { - return any.err -} - -func (any *numberLazyAny) ToBool() bool { - return any.ToFloat64() != 0 -} - -func (any *numberLazyAny) ToInt() int { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadInt() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToInt32() int32 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadInt32() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToInt64() int64 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadInt64() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToUint() uint { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadUint() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToUint32() uint32 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadUint32() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToUint64() uint64 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadUint64() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToFloat32() float32 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadFloat32() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToFloat64() float64 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadFloat64() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToString() string { - return *(*string)(unsafe.Pointer(&any.buf)) -} - -func (any *numberLazyAny) WriteTo(stream *Stream) { - stream.Write(any.buf) -} - -func (any *numberLazyAny) GetInterface() interface{} { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.Read() -} diff --git a/vendor/github.com/json-iterator/go/any_object.go b/vendor/github.com/json-iterator/go/any_object.go deleted file mode 100644 index c44ef5c..0000000 --- a/vendor/github.com/json-iterator/go/any_object.go +++ /dev/null @@ -1,374 +0,0 @@ -package jsoniter - -import ( - "reflect" - "unsafe" -) - -type objectLazyAny struct { - baseAny - cfg *frozenConfig - buf []byte - err error -} - -func (any *objectLazyAny) ValueType() ValueType { - return ObjectValue -} - -func (any *objectLazyAny) MustBeValid() Any { - return any -} - -func (any *objectLazyAny) LastError() error { - return any.err -} - -func (any *objectLazyAny) ToBool() bool { - return true -} - -func (any *objectLazyAny) ToInt() int { - return 0 -} - -func (any *objectLazyAny) ToInt32() int32 { - return 0 -} - -func (any *objectLazyAny) ToInt64() int64 { - return 0 -} - -func (any *objectLazyAny) ToUint() uint { - return 0 -} - -func (any *objectLazyAny) ToUint32() uint32 { - return 0 -} - -func (any *objectLazyAny) ToUint64() uint64 { - return 0 -} - -func (any *objectLazyAny) ToFloat32() float32 { - return 0 -} - -func (any *objectLazyAny) ToFloat64() float64 { - return 0 -} - -func (any *objectLazyAny) ToString() string { - return *(*string)(unsafe.Pointer(&any.buf)) -} - -func (any *objectLazyAny) ToVal(obj interface{}) { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadVal(obj) -} - -func (any *objectLazyAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case string: - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - valueBytes := locateObjectField(iter, firstPath) - if valueBytes == nil { - return newInvalidAny(path) - } - iter.ResetBytes(valueBytes) - return locatePath(iter, path[1:]) - case int32: - if '*' == firstPath { - mappedAll := map[string]Any{} - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadMapCB(func(iter *Iterator, field string) bool { - mapped := locatePath(iter, path[1:]) - if mapped.ValueType() != InvalidValue { - mappedAll[field] = mapped - } - return true - }) - return wrapMap(mappedAll) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *objectLazyAny) Keys() []string { - keys := []string{} - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadMapCB(func(iter *Iterator, field string) bool { - iter.Skip() - keys = append(keys, field) - return true - }) - return keys -} - -func (any *objectLazyAny) Size() int { - size := 0 - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadObjectCB(func(iter *Iterator, field string) bool { - iter.Skip() - size++ - return true - }) - return size -} - -func (any *objectLazyAny) WriteTo(stream *Stream) { - stream.Write(any.buf) -} - -func (any *objectLazyAny) GetInterface() interface{} { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.Read() -} - -type objectAny struct { - baseAny - err error - val reflect.Value -} - -func wrapStruct(val interface{}) *objectAny { - return &objectAny{baseAny{}, nil, reflect.ValueOf(val)} -} - -func (any *objectAny) ValueType() ValueType { - return ObjectValue -} - -func (any *objectAny) MustBeValid() Any { - return any -} - -func (any *objectAny) Parse() *Iterator { - return nil -} - -func (any *objectAny) LastError() error { - return any.err -} - -func (any *objectAny) ToBool() bool { - return any.val.NumField() != 0 -} - -func (any *objectAny) ToInt() int { - return 0 -} - -func (any *objectAny) ToInt32() int32 { - return 0 -} - -func (any *objectAny) ToInt64() int64 { - return 0 -} - -func (any *objectAny) ToUint() uint { - return 0 -} - -func (any *objectAny) ToUint32() uint32 { - return 0 -} - -func (any *objectAny) ToUint64() uint64 { - return 0 -} - -func (any *objectAny) ToFloat32() float32 { - return 0 -} - -func (any *objectAny) ToFloat64() float64 { - return 0 -} - -func (any *objectAny) ToString() string { - str, err := MarshalToString(any.val.Interface()) - any.err = err - return str -} - -func (any *objectAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case string: - field := any.val.FieldByName(firstPath) - if !field.IsValid() { - return newInvalidAny(path) - } - return Wrap(field.Interface()) - case int32: - if '*' == firstPath { - mappedAll := map[string]Any{} - for i := 0; i < any.val.NumField(); i++ { - field := any.val.Field(i) - if field.CanInterface() { - mapped := Wrap(field.Interface()).Get(path[1:]...) - if mapped.ValueType() != InvalidValue { - mappedAll[any.val.Type().Field(i).Name] = mapped - } - } - } - return wrapMap(mappedAll) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *objectAny) Keys() []string { - keys := make([]string, 0, any.val.NumField()) - for i := 0; i < any.val.NumField(); i++ { - keys = append(keys, any.val.Type().Field(i).Name) - } - return keys -} - -func (any *objectAny) Size() int { - return any.val.NumField() -} - -func (any *objectAny) WriteTo(stream *Stream) { - stream.WriteVal(any.val) -} - -func (any *objectAny) GetInterface() interface{} { - return any.val.Interface() -} - -type mapAny struct { - baseAny - err error - val reflect.Value -} - -func wrapMap(val interface{}) *mapAny { - return &mapAny{baseAny{}, nil, reflect.ValueOf(val)} -} - -func (any *mapAny) ValueType() ValueType { - return ObjectValue -} - -func (any *mapAny) MustBeValid() Any { - return any -} - -func (any *mapAny) Parse() *Iterator { - return nil -} - -func (any *mapAny) LastError() error { - return any.err -} - -func (any *mapAny) ToBool() bool { - return true -} - -func (any *mapAny) ToInt() int { - return 0 -} - -func (any *mapAny) ToInt32() int32 { - return 0 -} - -func (any *mapAny) ToInt64() int64 { - return 0 -} - -func (any *mapAny) ToUint() uint { - return 0 -} - -func (any *mapAny) ToUint32() uint32 { - return 0 -} - -func (any *mapAny) ToUint64() uint64 { - return 0 -} - -func (any *mapAny) ToFloat32() float32 { - return 0 -} - -func (any *mapAny) ToFloat64() float64 { - return 0 -} - -func (any *mapAny) ToString() string { - str, err := MarshalToString(any.val.Interface()) - any.err = err - return str -} - -func (any *mapAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case int32: - if '*' == firstPath { - mappedAll := map[string]Any{} - for _, key := range any.val.MapKeys() { - keyAsStr := key.String() - element := Wrap(any.val.MapIndex(key).Interface()) - mapped := element.Get(path[1:]...) - if mapped.ValueType() != InvalidValue { - mappedAll[keyAsStr] = mapped - } - } - return wrapMap(mappedAll) - } - return newInvalidAny(path) - default: - value := any.val.MapIndex(reflect.ValueOf(firstPath)) - if !value.IsValid() { - return newInvalidAny(path) - } - return Wrap(value.Interface()) - } -} - -func (any *mapAny) Keys() []string { - keys := make([]string, 0, any.val.Len()) - for _, key := range any.val.MapKeys() { - keys = append(keys, key.String()) - } - return keys -} - -func (any *mapAny) Size() int { - return any.val.Len() -} - -func (any *mapAny) WriteTo(stream *Stream) { - stream.WriteVal(any.val) -} - -func (any *mapAny) GetInterface() interface{} { - return any.val.Interface() -} diff --git a/vendor/github.com/json-iterator/go/any_str.go b/vendor/github.com/json-iterator/go/any_str.go deleted file mode 100644 index 1f12f66..0000000 --- a/vendor/github.com/json-iterator/go/any_str.go +++ /dev/null @@ -1,166 +0,0 @@ -package jsoniter - -import ( - "fmt" - "strconv" -) - -type stringAny struct { - baseAny - val string -} - -func (any *stringAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} -} - -func (any *stringAny) Parse() *Iterator { - return nil -} - -func (any *stringAny) ValueType() ValueType { - return StringValue -} - -func (any *stringAny) MustBeValid() Any { - return any -} - -func (any *stringAny) LastError() error { - return nil -} - -func (any *stringAny) ToBool() bool { - str := any.ToString() - if str == "0" { - return false - } - for _, c := range str { - switch c { - case ' ', '\n', '\r', '\t': - default: - return true - } - } - return false -} - -func (any *stringAny) ToInt() int { - return int(any.ToInt64()) - -} - -func (any *stringAny) ToInt32() int32 { - return int32(any.ToInt64()) -} - -func (any *stringAny) ToInt64() int64 { - if any.val == "" { - return 0 - } - - flag := 1 - startPos := 0 - if any.val[0] == '+' || any.val[0] == '-' { - startPos = 1 - } - - if any.val[0] == '-' { - flag = -1 - } - - endPos := startPos - for i := startPos; i < len(any.val); i++ { - if any.val[i] >= '0' && any.val[i] <= '9' { - endPos = i + 1 - } else { - break - } - } - parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64) - return int64(flag) * parsed -} - -func (any *stringAny) ToUint() uint { - return uint(any.ToUint64()) -} - -func (any *stringAny) ToUint32() uint32 { - return uint32(any.ToUint64()) -} - -func (any *stringAny) ToUint64() uint64 { - if any.val == "" { - return 0 - } - - startPos := 0 - - if any.val[0] == '-' { - return 0 - } - if any.val[0] == '+' { - startPos = 1 - } - - endPos := startPos - for i := startPos; i < len(any.val); i++ { - if any.val[i] >= '0' && any.val[i] <= '9' { - endPos = i + 1 - } else { - break - } - } - parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64) - return parsed -} - -func (any *stringAny) ToFloat32() float32 { - return float32(any.ToFloat64()) -} - -func (any *stringAny) ToFloat64() float64 { - if len(any.val) == 0 { - return 0 - } - - // first char invalid - if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') { - return 0 - } - - // extract valid num expression from string - // eg 123true => 123, -12.12xxa => -12.12 - endPos := 1 - for i := 1; i < len(any.val); i++ { - if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' { - endPos = i + 1 - continue - } - - // end position is the first char which is not digit - if any.val[i] >= '0' && any.val[i] <= '9' { - endPos = i + 1 - } else { - endPos = i - break - } - } - parsed, _ := strconv.ParseFloat(any.val[:endPos], 64) - return parsed -} - -func (any *stringAny) ToString() string { - return any.val -} - -func (any *stringAny) WriteTo(stream *Stream) { - stream.WriteString(any.val) -} - -func (any *stringAny) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_uint32.go b/vendor/github.com/json-iterator/go/any_uint32.go deleted file mode 100644 index 656bbd3..0000000 --- a/vendor/github.com/json-iterator/go/any_uint32.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type uint32Any struct { - baseAny - val uint32 -} - -func (any *uint32Any) LastError() error { - return nil -} - -func (any *uint32Any) ValueType() ValueType { - return NumberValue -} - -func (any *uint32Any) MustBeValid() Any { - return any -} - -func (any *uint32Any) ToBool() bool { - return any.val != 0 -} - -func (any *uint32Any) ToInt() int { - return int(any.val) -} - -func (any *uint32Any) ToInt32() int32 { - return int32(any.val) -} - -func (any *uint32Any) ToInt64() int64 { - return int64(any.val) -} - -func (any *uint32Any) ToUint() uint { - return uint(any.val) -} - -func (any *uint32Any) ToUint32() uint32 { - return any.val -} - -func (any *uint32Any) ToUint64() uint64 { - return uint64(any.val) -} - -func (any *uint32Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *uint32Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *uint32Any) ToString() string { - return strconv.FormatInt(int64(any.val), 10) -} - -func (any *uint32Any) WriteTo(stream *Stream) { - stream.WriteUint32(any.val) -} - -func (any *uint32Any) Parse() *Iterator { - return nil -} - -func (any *uint32Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_uint64.go b/vendor/github.com/json-iterator/go/any_uint64.go deleted file mode 100644 index 7df2fce..0000000 --- a/vendor/github.com/json-iterator/go/any_uint64.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type uint64Any struct { - baseAny - val uint64 -} - -func (any *uint64Any) LastError() error { - return nil -} - -func (any *uint64Any) ValueType() ValueType { - return NumberValue -} - -func (any *uint64Any) MustBeValid() Any { - return any -} - -func (any *uint64Any) ToBool() bool { - return any.val != 0 -} - -func (any *uint64Any) ToInt() int { - return int(any.val) -} - -func (any *uint64Any) ToInt32() int32 { - return int32(any.val) -} - -func (any *uint64Any) ToInt64() int64 { - return int64(any.val) -} - -func (any *uint64Any) ToUint() uint { - return uint(any.val) -} - -func (any *uint64Any) ToUint32() uint32 { - return uint32(any.val) -} - -func (any *uint64Any) ToUint64() uint64 { - return any.val -} - -func (any *uint64Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *uint64Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *uint64Any) ToString() string { - return strconv.FormatUint(any.val, 10) -} - -func (any *uint64Any) WriteTo(stream *Stream) { - stream.WriteUint64(any.val) -} - -func (any *uint64Any) Parse() *Iterator { - return nil -} - -func (any *uint64Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/build.sh b/vendor/github.com/json-iterator/go/build.sh deleted file mode 100644 index b45ef68..0000000 --- a/vendor/github.com/json-iterator/go/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -e -set -x - -if [ ! -d /tmp/build-golang/src/github.com/json-iterator ]; then - mkdir -p /tmp/build-golang/src/github.com/json-iterator - ln -s $PWD /tmp/build-golang/src/github.com/json-iterator/go -fi -export GOPATH=/tmp/build-golang -go get -u github.com/golang/dep/cmd/dep -cd /tmp/build-golang/src/github.com/json-iterator/go -exec $GOPATH/bin/dep ensure -update diff --git a/vendor/github.com/json-iterator/go/config.go b/vendor/github.com/json-iterator/go/config.go deleted file mode 100644 index 2adcdc3..0000000 --- a/vendor/github.com/json-iterator/go/config.go +++ /dev/null @@ -1,375 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "io" - "reflect" - "sync" - "unsafe" - - "github.com/modern-go/concurrent" - "github.com/modern-go/reflect2" -) - -// Config customize how the API should behave. -// The API is created from Config by Froze. -type Config struct { - IndentionStep int - MarshalFloatWith6Digits bool - EscapeHTML bool - SortMapKeys bool - UseNumber bool - DisallowUnknownFields bool - TagKey string - OnlyTaggedField bool - ValidateJsonRawMessage bool - ObjectFieldMustBeSimpleString bool - CaseSensitive bool -} - -// API the public interface of this package. -// Primary Marshal and Unmarshal. -type API interface { - IteratorPool - StreamPool - MarshalToString(v interface{}) (string, error) - Marshal(v interface{}) ([]byte, error) - MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) - UnmarshalFromString(str string, v interface{}) error - Unmarshal(data []byte, v interface{}) error - Get(data []byte, path ...interface{}) Any - NewEncoder(writer io.Writer) *Encoder - NewDecoder(reader io.Reader) *Decoder - Valid(data []byte) bool - RegisterExtension(extension Extension) - DecoderOf(typ reflect2.Type) ValDecoder - EncoderOf(typ reflect2.Type) ValEncoder -} - -// ConfigDefault the default API -var ConfigDefault = Config{ - EscapeHTML: true, -}.Froze() - -// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior -var ConfigCompatibleWithStandardLibrary = Config{ - EscapeHTML: true, - SortMapKeys: true, - ValidateJsonRawMessage: true, -}.Froze() - -// ConfigFastest marshals float with only 6 digits precision -var ConfigFastest = Config{ - EscapeHTML: false, - MarshalFloatWith6Digits: true, // will lose precession - ObjectFieldMustBeSimpleString: true, // do not unescape object field -}.Froze() - -type frozenConfig struct { - configBeforeFrozen Config - sortMapKeys bool - indentionStep int - objectFieldMustBeSimpleString bool - onlyTaggedField bool - disallowUnknownFields bool - decoderCache *concurrent.Map - encoderCache *concurrent.Map - encoderExtension Extension - decoderExtension Extension - extraExtensions []Extension - streamPool *sync.Pool - iteratorPool *sync.Pool - caseSensitive bool -} - -func (cfg *frozenConfig) initCache() { - cfg.decoderCache = concurrent.NewMap() - cfg.encoderCache = concurrent.NewMap() -} - -func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) { - cfg.decoderCache.Store(cacheKey, decoder) -} - -func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) { - cfg.encoderCache.Store(cacheKey, encoder) -} - -func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder { - decoder, found := cfg.decoderCache.Load(cacheKey) - if found { - return decoder.(ValDecoder) - } - return nil -} - -func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { - encoder, found := cfg.encoderCache.Load(cacheKey) - if found { - return encoder.(ValEncoder) - } - return nil -} - -var cfgCache = concurrent.NewMap() - -func getFrozenConfigFromCache(cfg Config) *frozenConfig { - obj, found := cfgCache.Load(cfg) - if found { - return obj.(*frozenConfig) - } - return nil -} - -func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { - cfgCache.Store(cfg, frozenConfig) -} - -// Froze forge API from config -func (cfg Config) Froze() API { - api := &frozenConfig{ - sortMapKeys: cfg.SortMapKeys, - indentionStep: cfg.IndentionStep, - objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString, - onlyTaggedField: cfg.OnlyTaggedField, - disallowUnknownFields: cfg.DisallowUnknownFields, - caseSensitive: cfg.CaseSensitive, - } - api.streamPool = &sync.Pool{ - New: func() interface{} { - return NewStream(api, nil, 512) - }, - } - api.iteratorPool = &sync.Pool{ - New: func() interface{} { - return NewIterator(api) - }, - } - api.initCache() - encoderExtension := EncoderExtension{} - decoderExtension := DecoderExtension{} - if cfg.MarshalFloatWith6Digits { - api.marshalFloatWith6Digits(encoderExtension) - } - if cfg.EscapeHTML { - api.escapeHTML(encoderExtension) - } - if cfg.UseNumber { - api.useNumber(decoderExtension) - } - if cfg.ValidateJsonRawMessage { - api.validateJsonRawMessage(encoderExtension) - } - api.encoderExtension = encoderExtension - api.decoderExtension = decoderExtension - api.configBeforeFrozen = cfg - return api -} - -func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig { - api := getFrozenConfigFromCache(cfg) - if api != nil { - return api - } - api = cfg.Froze().(*frozenConfig) - for _, extension := range extraExtensions { - api.RegisterExtension(extension) - } - addFrozenConfigToCache(cfg, api) - return api -} - -func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) { - encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { - rawMessage := *(*json.RawMessage)(ptr) - iter := cfg.BorrowIterator([]byte(rawMessage)) - defer cfg.ReturnIterator(iter) - iter.Read() - if iter.Error != nil && iter.Error != io.EOF { - stream.WriteRaw("null") - } else { - stream.WriteRaw(string(rawMessage)) - } - }, func(ptr unsafe.Pointer) bool { - return len(*((*json.RawMessage)(ptr))) == 0 - }} - extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder - extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder -} - -func (cfg *frozenConfig) useNumber(extension DecoderExtension) { - extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { - exitingValue := *((*interface{})(ptr)) - if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr { - iter.ReadVal(exitingValue) - return - } - if iter.WhatIsNext() == NumberValue { - *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) - } else { - *((*interface{})(ptr)) = iter.Read() - } - }} -} -func (cfg *frozenConfig) getTagKey() string { - tagKey := cfg.configBeforeFrozen.TagKey - if tagKey == "" { - return "json" - } - return tagKey -} - -func (cfg *frozenConfig) RegisterExtension(extension Extension) { - cfg.extraExtensions = append(cfg.extraExtensions, extension) - copied := cfg.configBeforeFrozen - cfg.configBeforeFrozen = copied -} - -type lossyFloat32Encoder struct { -} - -func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat32Lossy(*((*float32)(ptr))) -} - -func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float32)(ptr)) == 0 -} - -type lossyFloat64Encoder struct { -} - -func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat64Lossy(*((*float64)(ptr))) -} - -func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float64)(ptr)) == 0 -} - -// EnableLossyFloatMarshalling keeps 10**(-6) precision -// for float variables for better performance. -func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) { - // for better performance - extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{} - extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{} -} - -type htmlEscapedStringEncoder struct { -} - -func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - str := *((*string)(ptr)) - stream.WriteStringWithHTMLEscaped(str) -} - -func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*string)(ptr)) == "" -} - -func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) { - encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{} -} - -func (cfg *frozenConfig) cleanDecoders() { - typeDecoders = map[string]ValDecoder{} - fieldDecoders = map[string]ValDecoder{} - *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) -} - -func (cfg *frozenConfig) cleanEncoders() { - typeEncoders = map[string]ValEncoder{} - fieldEncoders = map[string]ValEncoder{} - *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) -} - -func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { - stream := cfg.BorrowStream(nil) - defer cfg.ReturnStream(stream) - stream.WriteVal(v) - if stream.Error != nil { - return "", stream.Error - } - return string(stream.Buffer()), nil -} - -func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { - stream := cfg.BorrowStream(nil) - defer cfg.ReturnStream(stream) - stream.WriteVal(v) - if stream.Error != nil { - return nil, stream.Error - } - result := stream.Buffer() - copied := make([]byte, len(result)) - copy(copied, result) - return copied, nil -} - -func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - if prefix != "" { - panic("prefix is not supported") - } - for _, r := range indent { - if r != ' ' { - panic("indent can only be space") - } - } - newCfg := cfg.configBeforeFrozen - newCfg.IndentionStep = len(indent) - return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v) -} - -func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { - data := []byte(str) - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - iter.ReadVal(v) - c := iter.nextToken() - if c == 0 { - if iter.Error == io.EOF { - return nil - } - return iter.Error - } - iter.ReportError("Unmarshal", "there are bytes left after unmarshal") - return iter.Error -} - -func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - return locatePath(iter, path) -} - -func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - iter.ReadVal(v) - c := iter.nextToken() - if c == 0 { - if iter.Error == io.EOF { - return nil - } - return iter.Error - } - iter.ReportError("Unmarshal", "there are bytes left after unmarshal") - return iter.Error -} - -func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { - stream := NewStream(cfg, writer, 512) - return &Encoder{stream} -} - -func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { - iter := Parse(cfg, reader, 512) - return &Decoder{iter} -} - -func (cfg *frozenConfig) Valid(data []byte) bool { - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - iter.Skip() - return iter.Error == nil -} diff --git a/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md b/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md deleted file mode 100644 index 3095662..0000000 --- a/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md +++ /dev/null @@ -1,7 +0,0 @@ -| json type \ dest type | bool | int | uint | float |string| -| --- | --- | --- | --- |--|--| -| number | positive => true
negative => true
zero => false| 23.2 => 23
-32.1 => -32| 12.1 => 12
-12.1 => 0|as normal|same as origin| -| string | empty string => false
string "0" => false
other strings => true | "123.32" => 123
"-123.4" => -123
"123.23xxxw" => 123
"abcde12" => 0
"-32.1" => -32| 13.2 => 13
-1.1 => 0 |12.1 => 12.1
-12.3 => -12.3
12.4xxa => 12.4
+1.1e2 =>110 |same as origin| -| bool | true => true
false => false| true => 1
false => 0 | true => 1
false => 0 |true => 1
false => 0|true => "true"
false => "false"| -| object | true | 0 | 0 |0|originnal json| -| array | empty array => false
nonempty array => true| [] => 0
[1,2] => 1 | [] => 0
[1,2] => 1 |[] => 0
[1,2] => 1|original json| \ No newline at end of file diff --git a/vendor/github.com/json-iterator/go/iter.go b/vendor/github.com/json-iterator/go/iter.go deleted file mode 100644 index 29b31cf..0000000 --- a/vendor/github.com/json-iterator/go/iter.go +++ /dev/null @@ -1,349 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "fmt" - "io" -) - -// ValueType the type for JSON element -type ValueType int - -const ( - // InvalidValue invalid JSON element - InvalidValue ValueType = iota - // StringValue JSON element "string" - StringValue - // NumberValue JSON element 100 or 0.10 - NumberValue - // NilValue JSON element null - NilValue - // BoolValue JSON element true or false - BoolValue - // ArrayValue JSON element [] - ArrayValue - // ObjectValue JSON element {} - ObjectValue -) - -var hexDigits []byte -var valueTypes []ValueType - -func init() { - hexDigits = make([]byte, 256) - for i := 0; i < len(hexDigits); i++ { - hexDigits[i] = 255 - } - for i := '0'; i <= '9'; i++ { - hexDigits[i] = byte(i - '0') - } - for i := 'a'; i <= 'f'; i++ { - hexDigits[i] = byte((i - 'a') + 10) - } - for i := 'A'; i <= 'F'; i++ { - hexDigits[i] = byte((i - 'A') + 10) - } - valueTypes = make([]ValueType, 256) - for i := 0; i < len(valueTypes); i++ { - valueTypes[i] = InvalidValue - } - valueTypes['"'] = StringValue - valueTypes['-'] = NumberValue - valueTypes['0'] = NumberValue - valueTypes['1'] = NumberValue - valueTypes['2'] = NumberValue - valueTypes['3'] = NumberValue - valueTypes['4'] = NumberValue - valueTypes['5'] = NumberValue - valueTypes['6'] = NumberValue - valueTypes['7'] = NumberValue - valueTypes['8'] = NumberValue - valueTypes['9'] = NumberValue - valueTypes['t'] = BoolValue - valueTypes['f'] = BoolValue - valueTypes['n'] = NilValue - valueTypes['['] = ArrayValue - valueTypes['{'] = ObjectValue -} - -// Iterator is a io.Reader like object, with JSON specific read functions. -// Error is not returned as return value, but stored as Error member on this iterator instance. -type Iterator struct { - cfg *frozenConfig - reader io.Reader - buf []byte - head int - tail int - depth int - captureStartedAt int - captured []byte - Error error - Attachment interface{} // open for customized decoder -} - -// NewIterator creates an empty Iterator instance -func NewIterator(cfg API) *Iterator { - return &Iterator{ - cfg: cfg.(*frozenConfig), - reader: nil, - buf: nil, - head: 0, - tail: 0, - depth: 0, - } -} - -// Parse creates an Iterator instance from io.Reader -func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { - return &Iterator{ - cfg: cfg.(*frozenConfig), - reader: reader, - buf: make([]byte, bufSize), - head: 0, - tail: 0, - depth: 0, - } -} - -// ParseBytes creates an Iterator instance from byte array -func ParseBytes(cfg API, input []byte) *Iterator { - return &Iterator{ - cfg: cfg.(*frozenConfig), - reader: nil, - buf: input, - head: 0, - tail: len(input), - depth: 0, - } -} - -// ParseString creates an Iterator instance from string -func ParseString(cfg API, input string) *Iterator { - return ParseBytes(cfg, []byte(input)) -} - -// Pool returns a pool can provide more iterator with same configuration -func (iter *Iterator) Pool() IteratorPool { - return iter.cfg -} - -// Reset reuse iterator instance by specifying another reader -func (iter *Iterator) Reset(reader io.Reader) *Iterator { - iter.reader = reader - iter.head = 0 - iter.tail = 0 - iter.depth = 0 - return iter -} - -// ResetBytes reuse iterator instance by specifying another byte array as input -func (iter *Iterator) ResetBytes(input []byte) *Iterator { - iter.reader = nil - iter.buf = input - iter.head = 0 - iter.tail = len(input) - iter.depth = 0 - return iter -} - -// WhatIsNext gets ValueType of relatively next json element -func (iter *Iterator) WhatIsNext() ValueType { - valueType := valueTypes[iter.nextToken()] - iter.unreadByte() - return valueType -} - -func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\t', '\r': - continue - } - iter.head = i - return false - } - return true -} - -func (iter *Iterator) isObjectEnd() bool { - c := iter.nextToken() - if c == ',' { - return false - } - if c == '}' { - return true - } - iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c})) - return true -} - -func (iter *Iterator) nextToken() byte { - // a variation of skip whitespaces, returning the next non-whitespace token - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\t', '\r': - continue - } - iter.head = i + 1 - return c - } - if !iter.loadMore() { - return 0 - } - } -} - -// ReportError record a error in iterator instance with current position. -func (iter *Iterator) ReportError(operation string, msg string) { - if iter.Error != nil { - if iter.Error != io.EOF { - return - } - } - peekStart := iter.head - 10 - if peekStart < 0 { - peekStart = 0 - } - peekEnd := iter.head + 10 - if peekEnd > iter.tail { - peekEnd = iter.tail - } - parsing := string(iter.buf[peekStart:peekEnd]) - contextStart := iter.head - 50 - if contextStart < 0 { - contextStart = 0 - } - contextEnd := iter.head + 50 - if contextEnd > iter.tail { - contextEnd = iter.tail - } - context := string(iter.buf[contextStart:contextEnd]) - iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", - operation, msg, iter.head-peekStart, parsing, context) -} - -// CurrentBuffer gets current buffer as string for debugging purpose -func (iter *Iterator) CurrentBuffer() string { - peekStart := iter.head - 10 - if peekStart < 0 { - peekStart = 0 - } - return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head, - string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) -} - -func (iter *Iterator) readByte() (ret byte) { - if iter.head == iter.tail { - if iter.loadMore() { - ret = iter.buf[iter.head] - iter.head++ - return ret - } - return 0 - } - ret = iter.buf[iter.head] - iter.head++ - return ret -} - -func (iter *Iterator) loadMore() bool { - if iter.reader == nil { - if iter.Error == nil { - iter.head = iter.tail - iter.Error = io.EOF - } - return false - } - if iter.captured != nil { - iter.captured = append(iter.captured, - iter.buf[iter.captureStartedAt:iter.tail]...) - iter.captureStartedAt = 0 - } - for { - n, err := iter.reader.Read(iter.buf) - if n == 0 { - if err != nil { - if iter.Error == nil { - iter.Error = err - } - return false - } - } else { - iter.head = 0 - iter.tail = n - return true - } - } -} - -func (iter *Iterator) unreadByte() { - if iter.Error != nil { - return - } - iter.head-- - return -} - -// Read read the next JSON element as generic interface{}. -func (iter *Iterator) Read() interface{} { - valueType := iter.WhatIsNext() - switch valueType { - case StringValue: - return iter.ReadString() - case NumberValue: - if iter.cfg.configBeforeFrozen.UseNumber { - return json.Number(iter.readNumberAsString()) - } - return iter.ReadFloat64() - case NilValue: - iter.skipFourBytes('n', 'u', 'l', 'l') - return nil - case BoolValue: - return iter.ReadBool() - case ArrayValue: - arr := []interface{}{} - iter.ReadArrayCB(func(iter *Iterator) bool { - var elem interface{} - iter.ReadVal(&elem) - arr = append(arr, elem) - return true - }) - return arr - case ObjectValue: - obj := map[string]interface{}{} - iter.ReadMapCB(func(Iter *Iterator, field string) bool { - var elem interface{} - iter.ReadVal(&elem) - obj[field] = elem - return true - }) - return obj - default: - iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) - return nil - } -} - -// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9 -const maxDepth = 10000 - -func (iter *Iterator) incrementDepth() (success bool) { - iter.depth++ - if iter.depth <= maxDepth { - return true - } - iter.ReportError("incrementDepth", "exceeded max depth") - return false -} - -func (iter *Iterator) decrementDepth() (success bool) { - iter.depth-- - if iter.depth >= 0 { - return true - } - iter.ReportError("decrementDepth", "unexpected negative nesting") - return false -} diff --git a/vendor/github.com/json-iterator/go/iter_array.go b/vendor/github.com/json-iterator/go/iter_array.go deleted file mode 100644 index 204fe0e..0000000 --- a/vendor/github.com/json-iterator/go/iter_array.go +++ /dev/null @@ -1,64 +0,0 @@ -package jsoniter - -// ReadArray read array element, tells if the array has more element to read. -func (iter *Iterator) ReadArray() (ret bool) { - c := iter.nextToken() - switch c { - case 'n': - iter.skipThreeBytes('u', 'l', 'l') - return false // null - case '[': - c = iter.nextToken() - if c != ']' { - iter.unreadByte() - return true - } - return false - case ']': - return false - case ',': - return true - default: - iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c})) - return - } -} - -// ReadArrayCB read array with callback -func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { - c := iter.nextToken() - if c == '[' { - if !iter.incrementDepth() { - return false - } - c = iter.nextToken() - if c != ']' { - iter.unreadByte() - if !callback(iter) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - for c == ',' { - if !callback(iter) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - } - if c != ']' { - iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) - iter.decrementDepth() - return false - } - return iter.decrementDepth() - } - return iter.decrementDepth() - } - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return true // null - } - iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c})) - return false -} diff --git a/vendor/github.com/json-iterator/go/iter_float.go b/vendor/github.com/json-iterator/go/iter_float.go deleted file mode 100644 index b975463..0000000 --- a/vendor/github.com/json-iterator/go/iter_float.go +++ /dev/null @@ -1,339 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "io" - "math/big" - "strconv" - "strings" - "unsafe" -) - -var floatDigits []int8 - -const invalidCharForNumber = int8(-1) -const endOfNumber = int8(-2) -const dotInNumber = int8(-3) - -func init() { - floatDigits = make([]int8, 256) - for i := 0; i < len(floatDigits); i++ { - floatDigits[i] = invalidCharForNumber - } - for i := int8('0'); i <= int8('9'); i++ { - floatDigits[i] = i - int8('0') - } - floatDigits[','] = endOfNumber - floatDigits[']'] = endOfNumber - floatDigits['}'] = endOfNumber - floatDigits[' '] = endOfNumber - floatDigits['\t'] = endOfNumber - floatDigits['\n'] = endOfNumber - floatDigits['.'] = dotInNumber -} - -// ReadBigFloat read big.Float -func (iter *Iterator) ReadBigFloat() (ret *big.Float) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return nil - } - prec := 64 - if len(str) > prec { - prec = len(str) - } - val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero) - if err != nil { - iter.Error = err - return nil - } - return val -} - -// ReadBigInt read big.Int -func (iter *Iterator) ReadBigInt() (ret *big.Int) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return nil - } - ret = big.NewInt(0) - var success bool - ret, success = ret.SetString(str, 10) - if !success { - iter.ReportError("ReadBigInt", "invalid big int") - return nil - } - return ret -} - -//ReadFloat32 read float32 -func (iter *Iterator) ReadFloat32() (ret float32) { - c := iter.nextToken() - if c == '-' { - return -iter.readPositiveFloat32() - } - iter.unreadByte() - return iter.readPositiveFloat32() -} - -func (iter *Iterator) readPositiveFloat32() (ret float32) { - i := iter.head - // first char - if i == iter.tail { - return iter.readFloat32SlowPath() - } - c := iter.buf[i] - i++ - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat32SlowPath() - case endOfNumber: - iter.ReportError("readFloat32", "empty number") - return - case dotInNumber: - iter.ReportError("readFloat32", "leading dot is invalid") - return - case 0: - if i == iter.tail { - return iter.readFloat32SlowPath() - } - c = iter.buf[i] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - iter.ReportError("readFloat32", "leading zero is invalid") - return - } - } - value := uint64(ind) - // chars before dot -non_decimal_loop: - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat32SlowPath() - case endOfNumber: - iter.head = i - return float32(value) - case dotInNumber: - break non_decimal_loop - } - if value > uint64SafeToMultiple10 { - return iter.readFloat32SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; - } - // chars after dot - if c == '.' { - i++ - decimalPlaces := 0 - if i == iter.tail { - return iter.readFloat32SlowPath() - } - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case endOfNumber: - if decimalPlaces > 0 && decimalPlaces < len(pow10) { - iter.head = i - return float32(float64(value) / float64(pow10[decimalPlaces])) - } - // too many decimal places - return iter.readFloat32SlowPath() - case invalidCharForNumber, dotInNumber: - return iter.readFloat32SlowPath() - } - decimalPlaces++ - if value > uint64SafeToMultiple10 { - return iter.readFloat32SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) - } - } - return iter.readFloat32SlowPath() -} - -func (iter *Iterator) readNumberAsString() (ret string) { - strBuf := [16]byte{} - str := strBuf[0:0] -load_loop: - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - str = append(str, c) - continue - default: - iter.head = i - break load_loop - } - } - if !iter.loadMore() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF { - return - } - if len(str) == 0 { - iter.ReportError("readNumberAsString", "invalid number") - } - return *(*string)(unsafe.Pointer(&str)) -} - -func (iter *Iterator) readFloat32SlowPath() (ret float32) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return - } - errMsg := validateFloat(str) - if errMsg != "" { - iter.ReportError("readFloat32SlowPath", errMsg) - return - } - val, err := strconv.ParseFloat(str, 32) - if err != nil { - iter.Error = err - return - } - return float32(val) -} - -// ReadFloat64 read float64 -func (iter *Iterator) ReadFloat64() (ret float64) { - c := iter.nextToken() - if c == '-' { - return -iter.readPositiveFloat64() - } - iter.unreadByte() - return iter.readPositiveFloat64() -} - -func (iter *Iterator) readPositiveFloat64() (ret float64) { - i := iter.head - // first char - if i == iter.tail { - return iter.readFloat64SlowPath() - } - c := iter.buf[i] - i++ - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat64SlowPath() - case endOfNumber: - iter.ReportError("readFloat64", "empty number") - return - case dotInNumber: - iter.ReportError("readFloat64", "leading dot is invalid") - return - case 0: - if i == iter.tail { - return iter.readFloat64SlowPath() - } - c = iter.buf[i] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - iter.ReportError("readFloat64", "leading zero is invalid") - return - } - } - value := uint64(ind) - // chars before dot -non_decimal_loop: - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat64SlowPath() - case endOfNumber: - iter.head = i - return float64(value) - case dotInNumber: - break non_decimal_loop - } - if value > uint64SafeToMultiple10 { - return iter.readFloat64SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; - } - // chars after dot - if c == '.' { - i++ - decimalPlaces := 0 - if i == iter.tail { - return iter.readFloat64SlowPath() - } - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case endOfNumber: - if decimalPlaces > 0 && decimalPlaces < len(pow10) { - iter.head = i - return float64(value) / float64(pow10[decimalPlaces]) - } - // too many decimal places - return iter.readFloat64SlowPath() - case invalidCharForNumber, dotInNumber: - return iter.readFloat64SlowPath() - } - decimalPlaces++ - if value > uint64SafeToMultiple10 { - return iter.readFloat64SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) - } - } - return iter.readFloat64SlowPath() -} - -func (iter *Iterator) readFloat64SlowPath() (ret float64) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return - } - errMsg := validateFloat(str) - if errMsg != "" { - iter.ReportError("readFloat64SlowPath", errMsg) - return - } - val, err := strconv.ParseFloat(str, 64) - if err != nil { - iter.Error = err - return - } - return val -} - -func validateFloat(str string) string { - // strconv.ParseFloat is not validating `1.` or `1.e1` - if len(str) == 0 { - return "empty number" - } - if str[0] == '-' { - return "-- is not valid" - } - dotPos := strings.IndexByte(str, '.') - if dotPos != -1 { - if dotPos == len(str)-1 { - return "dot can not be last character" - } - switch str[dotPos+1] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - return "missing digit after dot" - } - } - return "" -} - -// ReadNumber read json.Number -func (iter *Iterator) ReadNumber() (ret json.Number) { - return json.Number(iter.readNumberAsString()) -} diff --git a/vendor/github.com/json-iterator/go/iter_int.go b/vendor/github.com/json-iterator/go/iter_int.go deleted file mode 100644 index 2142320..0000000 --- a/vendor/github.com/json-iterator/go/iter_int.go +++ /dev/null @@ -1,345 +0,0 @@ -package jsoniter - -import ( - "math" - "strconv" -) - -var intDigits []int8 - -const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 -const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 - -func init() { - intDigits = make([]int8, 256) - for i := 0; i < len(intDigits); i++ { - intDigits[i] = invalidCharForNumber - } - for i := int8('0'); i <= int8('9'); i++ { - intDigits[i] = i - int8('0') - } -} - -// ReadUint read uint -func (iter *Iterator) ReadUint() uint { - if strconv.IntSize == 32 { - return uint(iter.ReadUint32()) - } - return uint(iter.ReadUint64()) -} - -// ReadInt read int -func (iter *Iterator) ReadInt() int { - if strconv.IntSize == 32 { - return int(iter.ReadInt32()) - } - return int(iter.ReadInt64()) -} - -// ReadInt8 read int8 -func (iter *Iterator) ReadInt8() (ret int8) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint32(iter.readByte()) - if val > math.MaxInt8+1 { - iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return -int8(val) - } - val := iter.readUint32(c) - if val > math.MaxInt8 { - iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int8(val) -} - -// ReadUint8 read uint8 -func (iter *Iterator) ReadUint8() (ret uint8) { - val := iter.readUint32(iter.nextToken()) - if val > math.MaxUint8 { - iter.ReportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return uint8(val) -} - -// ReadInt16 read int16 -func (iter *Iterator) ReadInt16() (ret int16) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint32(iter.readByte()) - if val > math.MaxInt16+1 { - iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return -int16(val) - } - val := iter.readUint32(c) - if val > math.MaxInt16 { - iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int16(val) -} - -// ReadUint16 read uint16 -func (iter *Iterator) ReadUint16() (ret uint16) { - val := iter.readUint32(iter.nextToken()) - if val > math.MaxUint16 { - iter.ReportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return uint16(val) -} - -// ReadInt32 read int32 -func (iter *Iterator) ReadInt32() (ret int32) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint32(iter.readByte()) - if val > math.MaxInt32+1 { - iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return -int32(val) - } - val := iter.readUint32(c) - if val > math.MaxInt32 { - iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int32(val) -} - -// ReadUint32 read uint32 -func (iter *Iterator) ReadUint32() (ret uint32) { - return iter.readUint32(iter.nextToken()) -} - -func (iter *Iterator) readUint32(c byte) (ret uint32) { - ind := intDigits[c] - if ind == 0 { - iter.assertInteger() - return 0 // single zero - } - if ind == invalidCharForNumber { - iter.ReportError("readUint32", "unexpected character: "+string([]byte{byte(ind)})) - return - } - value := uint32(ind) - if iter.tail-iter.head > 10 { - i := iter.head - ind2 := intDigits[iter.buf[i]] - if ind2 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - i++ - ind3 := intDigits[iter.buf[i]] - if ind3 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10 + uint32(ind2) - } - //iter.head = i + 1 - //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) - i++ - ind4 := intDigits[iter.buf[i]] - if ind4 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100 + uint32(ind2)*10 + uint32(ind3) - } - i++ - ind5 := intDigits[iter.buf[i]] - if ind5 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) - } - i++ - ind6 := intDigits[iter.buf[i]] - if ind6 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) - } - i++ - ind7 := intDigits[iter.buf[i]] - if ind7 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) - } - i++ - ind8 := intDigits[iter.buf[i]] - if ind8 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) - } - i++ - ind9 := intDigits[iter.buf[i]] - value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) - iter.head = i - if ind9 == invalidCharForNumber { - iter.assertInteger() - return value - } - } - for { - for i := iter.head; i < iter.tail; i++ { - ind = intDigits[iter.buf[i]] - if ind == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - if value > uint32SafeToMultiply10 { - value2 := (value << 3) + (value << 1) + uint32(ind) - if value2 < value { - iter.ReportError("readUint32", "overflow") - return - } - value = value2 - continue - } - value = (value << 3) + (value << 1) + uint32(ind) - } - if !iter.loadMore() { - iter.assertInteger() - return value - } - } -} - -// ReadInt64 read int64 -func (iter *Iterator) ReadInt64() (ret int64) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint64(iter.readByte()) - if val > math.MaxInt64+1 { - iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) - return - } - return -int64(val) - } - val := iter.readUint64(c) - if val > math.MaxInt64 { - iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) - return - } - return int64(val) -} - -// ReadUint64 read uint64 -func (iter *Iterator) ReadUint64() uint64 { - return iter.readUint64(iter.nextToken()) -} - -func (iter *Iterator) readUint64(c byte) (ret uint64) { - ind := intDigits[c] - if ind == 0 { - iter.assertInteger() - return 0 // single zero - } - if ind == invalidCharForNumber { - iter.ReportError("readUint64", "unexpected character: "+string([]byte{byte(ind)})) - return - } - value := uint64(ind) - if iter.tail-iter.head > 10 { - i := iter.head - ind2 := intDigits[iter.buf[i]] - if ind2 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - i++ - ind3 := intDigits[iter.buf[i]] - if ind3 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10 + uint64(ind2) - } - //iter.head = i + 1 - //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) - i++ - ind4 := intDigits[iter.buf[i]] - if ind4 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100 + uint64(ind2)*10 + uint64(ind3) - } - i++ - ind5 := intDigits[iter.buf[i]] - if ind5 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4) - } - i++ - ind6 := intDigits[iter.buf[i]] - if ind6 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5) - } - i++ - ind7 := intDigits[iter.buf[i]] - if ind7 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6) - } - i++ - ind8 := intDigits[iter.buf[i]] - if ind8 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7) - } - i++ - ind9 := intDigits[iter.buf[i]] - value = value*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8) - iter.head = i - if ind9 == invalidCharForNumber { - iter.assertInteger() - return value - } - } - for { - for i := iter.head; i < iter.tail; i++ { - ind = intDigits[iter.buf[i]] - if ind == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - if value > uint64SafeToMultiple10 { - value2 := (value << 3) + (value << 1) + uint64(ind) - if value2 < value { - iter.ReportError("readUint64", "overflow") - return - } - value = value2 - continue - } - value = (value << 3) + (value << 1) + uint64(ind) - } - if !iter.loadMore() { - iter.assertInteger() - return value - } - } -} - -func (iter *Iterator) assertInteger() { - if iter.head < len(iter.buf) && iter.buf[iter.head] == '.' { - iter.ReportError("assertInteger", "can not decode float as int") - } -} diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go deleted file mode 100644 index 58ee89c..0000000 --- a/vendor/github.com/json-iterator/go/iter_object.go +++ /dev/null @@ -1,267 +0,0 @@ -package jsoniter - -import ( - "fmt" - "strings" -) - -// ReadObject read one field from object. -// If object ended, returns empty string. -// Otherwise, returns the field name. -func (iter *Iterator) ReadObject() (ret string) { - c := iter.nextToken() - switch c { - case 'n': - iter.skipThreeBytes('u', 'l', 'l') - return "" // null - case '{': - c = iter.nextToken() - if c == '"' { - iter.unreadByte() - field := iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - return field - } - if c == '}' { - return "" // end of object - } - iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c})) - return - case ',': - field := iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - return field - case '}': - return "" // end of object - default: - iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) - return - } -} - -// CaseInsensitive -func (iter *Iterator) readFieldHash() int64 { - hash := int64(0x811c9dc5) - c := iter.nextToken() - if c != '"' { - iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) - return 0 - } - for { - for i := iter.head; i < iter.tail; i++ { - // require ascii string and no escape - b := iter.buf[i] - if b == '\\' { - iter.head = i - for _, b := range iter.readStringSlowPath() { - if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { - b += 'a' - 'A' - } - hash ^= int64(b) - hash *= 0x1000193 - } - c = iter.nextToken() - if c != ':' { - iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) - return 0 - } - return hash - } - if b == '"' { - iter.head = i + 1 - c = iter.nextToken() - if c != ':' { - iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) - return 0 - } - return hash - } - if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { - b += 'a' - 'A' - } - hash ^= int64(b) - hash *= 0x1000193 - } - if !iter.loadMore() { - iter.ReportError("readFieldHash", `incomplete field name`) - return 0 - } - } -} - -func calcHash(str string, caseSensitive bool) int64 { - if !caseSensitive { - str = strings.ToLower(str) - } - hash := int64(0x811c9dc5) - for _, b := range []byte(str) { - hash ^= int64(b) - hash *= 0x1000193 - } - return int64(hash) -} - -// ReadObjectCB read object with callback, the key is ascii only and field name not copied -func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { - c := iter.nextToken() - var field string - if c == '{' { - if !iter.incrementDepth() { - return false - } - c = iter.nextToken() - if c == '"' { - iter.unreadByte() - field = iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - for c == ',' { - field = iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - } - if c != '}' { - iter.ReportError("ReadObjectCB", `object not ended with }`) - iter.decrementDepth() - return false - } - return iter.decrementDepth() - } - if c == '}' { - return iter.decrementDepth() - } - iter.ReportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c})) - iter.decrementDepth() - return false - } - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return true // null - } - iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) - return false -} - -// ReadMapCB read map with callback, the key can be any string -func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { - c := iter.nextToken() - if c == '{' { - if !iter.incrementDepth() { - return false - } - c = iter.nextToken() - if c == '"' { - iter.unreadByte() - field := iter.ReadString() - if iter.nextToken() != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - iter.decrementDepth() - return false - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - for c == ',' { - field = iter.ReadString() - if iter.nextToken() != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - iter.decrementDepth() - return false - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - } - if c != '}' { - iter.ReportError("ReadMapCB", `object not ended with }`) - iter.decrementDepth() - return false - } - return iter.decrementDepth() - } - if c == '}' { - return iter.decrementDepth() - } - iter.ReportError("ReadMapCB", `expect " after {, but found `+string([]byte{c})) - iter.decrementDepth() - return false - } - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return true // null - } - iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) - return false -} - -func (iter *Iterator) readObjectStart() bool { - c := iter.nextToken() - if c == '{' { - c = iter.nextToken() - if c == '}' { - return false - } - iter.unreadByte() - return true - } else if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return false - } - iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c})) - return false -} - -func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { - str := iter.ReadStringAsSlice() - if iter.skipWhitespacesWithoutLoadMore() { - if ret == nil { - ret = make([]byte, len(str)) - copy(ret, str) - } - if !iter.loadMore() { - return - } - } - if iter.buf[iter.head] != ':' { - iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]})) - return - } - iter.head++ - if iter.skipWhitespacesWithoutLoadMore() { - if ret == nil { - ret = make([]byte, len(str)) - copy(ret, str) - } - if !iter.loadMore() { - return - } - } - if ret == nil { - return str - } - return ret -} diff --git a/vendor/github.com/json-iterator/go/iter_skip.go b/vendor/github.com/json-iterator/go/iter_skip.go deleted file mode 100644 index e91eefb..0000000 --- a/vendor/github.com/json-iterator/go/iter_skip.go +++ /dev/null @@ -1,130 +0,0 @@ -package jsoniter - -import "fmt" - -// ReadNil reads a json object as nil and -// returns whether it's a nil or not -func (iter *Iterator) ReadNil() (ret bool) { - c := iter.nextToken() - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') // null - return true - } - iter.unreadByte() - return false -} - -// ReadBool reads a json object as BoolValue -func (iter *Iterator) ReadBool() (ret bool) { - c := iter.nextToken() - if c == 't' { - iter.skipThreeBytes('r', 'u', 'e') - return true - } - if c == 'f' { - iter.skipFourBytes('a', 'l', 's', 'e') - return false - } - iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c})) - return -} - -// SkipAndReturnBytes skip next JSON element, and return its content as []byte. -// The []byte can be kept, it is a copy of data. -func (iter *Iterator) SkipAndReturnBytes() []byte { - iter.startCapture(iter.head) - iter.Skip() - return iter.stopCapture() -} - -// SkipAndAppendBytes skips next JSON element and appends its content to -// buffer, returning the result. -func (iter *Iterator) SkipAndAppendBytes(buf []byte) []byte { - iter.startCaptureTo(buf, iter.head) - iter.Skip() - return iter.stopCapture() -} - -func (iter *Iterator) startCaptureTo(buf []byte, captureStartedAt int) { - if iter.captured != nil { - panic("already in capture mode") - } - iter.captureStartedAt = captureStartedAt - iter.captured = buf -} - -func (iter *Iterator) startCapture(captureStartedAt int) { - iter.startCaptureTo(make([]byte, 0, 32), captureStartedAt) -} - -func (iter *Iterator) stopCapture() []byte { - if iter.captured == nil { - panic("not in capture mode") - } - captured := iter.captured - remaining := iter.buf[iter.captureStartedAt:iter.head] - iter.captureStartedAt = -1 - iter.captured = nil - return append(captured, remaining...) -} - -// Skip skips a json object and positions to relatively the next json object -func (iter *Iterator) Skip() { - c := iter.nextToken() - switch c { - case '"': - iter.skipString() - case 'n': - iter.skipThreeBytes('u', 'l', 'l') // null - case 't': - iter.skipThreeBytes('r', 'u', 'e') // true - case 'f': - iter.skipFourBytes('a', 'l', 's', 'e') // false - case '0': - iter.unreadByte() - iter.ReadFloat32() - case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': - iter.skipNumber() - case '[': - iter.skipArray() - case '{': - iter.skipObject() - default: - iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) - return - } -} - -func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) { - if iter.readByte() != b1 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } - if iter.readByte() != b2 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } - if iter.readByte() != b3 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } - if iter.readByte() != b4 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } -} - -func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) { - if iter.readByte() != b1 { - iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) - return - } - if iter.readByte() != b2 { - iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) - return - } - if iter.readByte() != b3 { - iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) - return - } -} diff --git a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go deleted file mode 100644 index 9303de4..0000000 --- a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go +++ /dev/null @@ -1,163 +0,0 @@ -//+build jsoniter_sloppy - -package jsoniter - -// sloppy but faster implementation, do not validate the input json - -func (iter *Iterator) skipNumber() { - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\r', '\t', ',', '}', ']': - iter.head = i - return - } - } - if !iter.loadMore() { - return - } - } -} - -func (iter *Iterator) skipArray() { - level := 1 - if !iter.incrementDepth() { - return - } - for { - for i := iter.head; i < iter.tail; i++ { - switch iter.buf[i] { - case '"': // If inside string, skip it - iter.head = i + 1 - iter.skipString() - i = iter.head - 1 // it will be i++ soon - case '[': // If open symbol, increase level - level++ - if !iter.incrementDepth() { - return - } - case ']': // If close symbol, increase level - level-- - if !iter.decrementDepth() { - return - } - - // If we have returned to the original level, we're done - if level == 0 { - iter.head = i + 1 - return - } - } - } - if !iter.loadMore() { - iter.ReportError("skipObject", "incomplete array") - return - } - } -} - -func (iter *Iterator) skipObject() { - level := 1 - if !iter.incrementDepth() { - return - } - - for { - for i := iter.head; i < iter.tail; i++ { - switch iter.buf[i] { - case '"': // If inside string, skip it - iter.head = i + 1 - iter.skipString() - i = iter.head - 1 // it will be i++ soon - case '{': // If open symbol, increase level - level++ - if !iter.incrementDepth() { - return - } - case '}': // If close symbol, increase level - level-- - if !iter.decrementDepth() { - return - } - - // If we have returned to the original level, we're done - if level == 0 { - iter.head = i + 1 - return - } - } - } - if !iter.loadMore() { - iter.ReportError("skipObject", "incomplete object") - return - } - } -} - -func (iter *Iterator) skipString() { - for { - end, escaped := iter.findStringEnd() - if end == -1 { - if !iter.loadMore() { - iter.ReportError("skipString", "incomplete string") - return - } - if escaped { - iter.head = 1 // skip the first char as last char read is \ - } - } else { - iter.head = end - return - } - } -} - -// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go -// Tries to find the end of string -// Support if string contains escaped quote symbols. -func (iter *Iterator) findStringEnd() (int, bool) { - escaped := false - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - if c == '"' { - if !escaped { - return i + 1, false - } - j := i - 1 - for { - if j < iter.head || iter.buf[j] != '\\' { - // even number of backslashes - // either end of buffer, or " found - return i + 1, true - } - j-- - if j < iter.head || iter.buf[j] != '\\' { - // odd number of backslashes - // it is \" or \\\" - break - } - j-- - } - } else if c == '\\' { - escaped = true - } - } - j := iter.tail - 1 - for { - if j < iter.head || iter.buf[j] != '\\' { - // even number of backslashes - // either end of buffer, or " found - return -1, false // do not end with \ - } - j-- - if j < iter.head || iter.buf[j] != '\\' { - // odd number of backslashes - // it is \" or \\\" - break - } - j-- - - } - return -1, true // end with \ -} diff --git a/vendor/github.com/json-iterator/go/iter_skip_strict.go b/vendor/github.com/json-iterator/go/iter_skip_strict.go deleted file mode 100644 index 6cf66d0..0000000 --- a/vendor/github.com/json-iterator/go/iter_skip_strict.go +++ /dev/null @@ -1,99 +0,0 @@ -//+build !jsoniter_sloppy - -package jsoniter - -import ( - "fmt" - "io" -) - -func (iter *Iterator) skipNumber() { - if !iter.trySkipNumber() { - iter.unreadByte() - if iter.Error != nil && iter.Error != io.EOF { - return - } - iter.ReadFloat64() - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = nil - iter.ReadBigFloat() - } - } -} - -func (iter *Iterator) trySkipNumber() bool { - dotFound := false - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - case '.': - if dotFound { - iter.ReportError("validateNumber", `more than one dot found in number`) - return true // already failed - } - if i+1 == iter.tail { - return false - } - c = iter.buf[i+1] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - iter.ReportError("validateNumber", `missing digit after dot`) - return true // already failed - } - dotFound = true - default: - switch c { - case ',', ']', '}', ' ', '\t', '\n', '\r': - if iter.head == i { - return false // if - without following digits - } - iter.head = i - return true // must be valid - } - return false // may be invalid - } - } - return false -} - -func (iter *Iterator) skipString() { - if !iter.trySkipString() { - iter.unreadByte() - iter.ReadString() - } -} - -func (iter *Iterator) trySkipString() bool { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - if c == '"' { - iter.head = i + 1 - return true // valid - } else if c == '\\' { - return false - } else if c < ' ' { - iter.ReportError("trySkipString", - fmt.Sprintf(`invalid control character found: %d`, c)) - return true // already failed - } - } - return false -} - -func (iter *Iterator) skipObject() { - iter.unreadByte() - iter.ReadObjectCB(func(iter *Iterator, field string) bool { - iter.Skip() - return true - }) -} - -func (iter *Iterator) skipArray() { - iter.unreadByte() - iter.ReadArrayCB(func(iter *Iterator) bool { - iter.Skip() - return true - }) -} diff --git a/vendor/github.com/json-iterator/go/iter_str.go b/vendor/github.com/json-iterator/go/iter_str.go deleted file mode 100644 index adc487e..0000000 --- a/vendor/github.com/json-iterator/go/iter_str.go +++ /dev/null @@ -1,215 +0,0 @@ -package jsoniter - -import ( - "fmt" - "unicode/utf16" -) - -// ReadString read string from iterator -func (iter *Iterator) ReadString() (ret string) { - c := iter.nextToken() - if c == '"' { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - if c == '"' { - ret = string(iter.buf[iter.head:i]) - iter.head = i + 1 - return ret - } else if c == '\\' { - break - } else if c < ' ' { - iter.ReportError("ReadString", - fmt.Sprintf(`invalid control character found: %d`, c)) - return - } - } - return iter.readStringSlowPath() - } else if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return "" - } - iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c})) - return -} - -func (iter *Iterator) readStringSlowPath() (ret string) { - var str []byte - var c byte - for iter.Error == nil { - c = iter.readByte() - if c == '"' { - return string(str) - } - if c == '\\' { - c = iter.readByte() - str = iter.readEscapedChar(c, str) - } else { - str = append(str, c) - } - } - iter.ReportError("readStringSlowPath", "unexpected end of input") - return -} - -func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte { - switch c { - case 'u': - r := iter.readU4() - if utf16.IsSurrogate(r) { - c = iter.readByte() - if iter.Error != nil { - return nil - } - if c != '\\' { - iter.unreadByte() - str = appendRune(str, r) - return str - } - c = iter.readByte() - if iter.Error != nil { - return nil - } - if c != 'u' { - str = appendRune(str, r) - return iter.readEscapedChar(c, str) - } - r2 := iter.readU4() - if iter.Error != nil { - return nil - } - combined := utf16.DecodeRune(r, r2) - if combined == '\uFFFD' { - str = appendRune(str, r) - str = appendRune(str, r2) - } else { - str = appendRune(str, combined) - } - } else { - str = appendRune(str, r) - } - case '"': - str = append(str, '"') - case '\\': - str = append(str, '\\') - case '/': - str = append(str, '/') - case 'b': - str = append(str, '\b') - case 'f': - str = append(str, '\f') - case 'n': - str = append(str, '\n') - case 'r': - str = append(str, '\r') - case 't': - str = append(str, '\t') - default: - iter.ReportError("readEscapedChar", - `invalid escape char after \`) - return nil - } - return str -} - -// ReadStringAsSlice read string from iterator without copying into string form. -// The []byte can not be kept, as it will change after next iterator call. -func (iter *Iterator) ReadStringAsSlice() (ret []byte) { - c := iter.nextToken() - if c == '"' { - for i := iter.head; i < iter.tail; i++ { - // require ascii string and no escape - // for: field name, base64, number - if iter.buf[i] == '"' { - // fast path: reuse the underlying buffer - ret = iter.buf[iter.head:i] - iter.head = i + 1 - return ret - } - } - readLen := iter.tail - iter.head - copied := make([]byte, readLen, readLen*2) - copy(copied, iter.buf[iter.head:iter.tail]) - iter.head = iter.tail - for iter.Error == nil { - c := iter.readByte() - if c == '"' { - return copied - } - copied = append(copied, c) - } - return copied - } - iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c})) - return -} - -func (iter *Iterator) readU4() (ret rune) { - for i := 0; i < 4; i++ { - c := iter.readByte() - if iter.Error != nil { - return - } - if c >= '0' && c <= '9' { - ret = ret*16 + rune(c-'0') - } else if c >= 'a' && c <= 'f' { - ret = ret*16 + rune(c-'a'+10) - } else if c >= 'A' && c <= 'F' { - ret = ret*16 + rune(c-'A'+10) - } else { - iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) - return - } - } - return ret -} - -const ( - t1 = 0x00 // 0000 0000 - tx = 0x80 // 1000 0000 - t2 = 0xC0 // 1100 0000 - t3 = 0xE0 // 1110 0000 - t4 = 0xF0 // 1111 0000 - t5 = 0xF8 // 1111 1000 - - maskx = 0x3F // 0011 1111 - mask2 = 0x1F // 0001 1111 - mask3 = 0x0F // 0000 1111 - mask4 = 0x07 // 0000 0111 - - rune1Max = 1<<7 - 1 - rune2Max = 1<<11 - 1 - rune3Max = 1<<16 - 1 - - surrogateMin = 0xD800 - surrogateMax = 0xDFFF - - maxRune = '\U0010FFFF' // Maximum valid Unicode code point. - runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" -) - -func appendRune(p []byte, r rune) []byte { - // Negative values are erroneous. Making it unsigned addresses the problem. - switch i := uint32(r); { - case i <= rune1Max: - p = append(p, byte(r)) - return p - case i <= rune2Max: - p = append(p, t2|byte(r>>6)) - p = append(p, tx|byte(r)&maskx) - return p - case i > maxRune, surrogateMin <= i && i <= surrogateMax: - r = runeError - fallthrough - case i <= rune3Max: - p = append(p, t3|byte(r>>12)) - p = append(p, tx|byte(r>>6)&maskx) - p = append(p, tx|byte(r)&maskx) - return p - default: - p = append(p, t4|byte(r>>18)) - p = append(p, tx|byte(r>>12)&maskx) - p = append(p, tx|byte(r>>6)&maskx) - p = append(p, tx|byte(r)&maskx) - return p - } -} diff --git a/vendor/github.com/json-iterator/go/jsoniter.go b/vendor/github.com/json-iterator/go/jsoniter.go deleted file mode 100644 index c2934f9..0000000 --- a/vendor/github.com/json-iterator/go/jsoniter.go +++ /dev/null @@ -1,18 +0,0 @@ -// Package jsoniter implements encoding and decoding of JSON as defined in -// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json. -// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter -// and variable type declarations (if any). -// jsoniter interfaces gives 100% compatibility with code using standard lib. -// -// "JSON and Go" -// (https://golang.org/doc/articles/json_and_go.html) -// gives a description of how Marshal/Unmarshal operate -// between arbitrary or predefined json objects and bytes, -// and it applies to jsoniter.Marshal/Unmarshal as well. -// -// Besides, jsoniter.Iterator provides a different set of interfaces -// iterating given bytes/string/reader -// and yielding parsed elements one by one. -// This set of interfaces reads input as required and gives -// better performance. -package jsoniter diff --git a/vendor/github.com/json-iterator/go/pool.go b/vendor/github.com/json-iterator/go/pool.go deleted file mode 100644 index e2389b5..0000000 --- a/vendor/github.com/json-iterator/go/pool.go +++ /dev/null @@ -1,42 +0,0 @@ -package jsoniter - -import ( - "io" -) - -// IteratorPool a thread safe pool of iterators with same configuration -type IteratorPool interface { - BorrowIterator(data []byte) *Iterator - ReturnIterator(iter *Iterator) -} - -// StreamPool a thread safe pool of streams with same configuration -type StreamPool interface { - BorrowStream(writer io.Writer) *Stream - ReturnStream(stream *Stream) -} - -func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { - stream := cfg.streamPool.Get().(*Stream) - stream.Reset(writer) - return stream -} - -func (cfg *frozenConfig) ReturnStream(stream *Stream) { - stream.out = nil - stream.Error = nil - stream.Attachment = nil - cfg.streamPool.Put(stream) -} - -func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator { - iter := cfg.iteratorPool.Get().(*Iterator) - iter.ResetBytes(data) - return iter -} - -func (cfg *frozenConfig) ReturnIterator(iter *Iterator) { - iter.Error = nil - iter.Attachment = nil - cfg.iteratorPool.Put(iter) -} diff --git a/vendor/github.com/json-iterator/go/reflect.go b/vendor/github.com/json-iterator/go/reflect.go deleted file mode 100644 index 74974ba..0000000 --- a/vendor/github.com/json-iterator/go/reflect.go +++ /dev/null @@ -1,337 +0,0 @@ -package jsoniter - -import ( - "fmt" - "reflect" - "unsafe" - - "github.com/modern-go/reflect2" -) - -// ValDecoder is an internal type registered to cache as needed. -// Don't confuse jsoniter.ValDecoder with json.Decoder. -// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link). -// -// Reflection on type to create decoders, which is then cached -// Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions -// 1. create instance of new value, for example *int will need a int to be allocated -// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New -// 3. assignment to map, both key and value will be reflect.Value -// For a simple struct binding, it will be reflect.Value free and allocation free -type ValDecoder interface { - Decode(ptr unsafe.Pointer, iter *Iterator) -} - -// ValEncoder is an internal type registered to cache as needed. -// Don't confuse jsoniter.ValEncoder with json.Encoder. -// For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link). -type ValEncoder interface { - IsEmpty(ptr unsafe.Pointer) bool - Encode(ptr unsafe.Pointer, stream *Stream) -} - -type checkIsEmpty interface { - IsEmpty(ptr unsafe.Pointer) bool -} - -type ctx struct { - *frozenConfig - prefix string - encoders map[reflect2.Type]ValEncoder - decoders map[reflect2.Type]ValDecoder -} - -func (b *ctx) caseSensitive() bool { - if b.frozenConfig == nil { - // default is case-insensitive - return false - } - return b.frozenConfig.caseSensitive -} - -func (b *ctx) append(prefix string) *ctx { - return &ctx{ - frozenConfig: b.frozenConfig, - prefix: b.prefix + " " + prefix, - encoders: b.encoders, - decoders: b.decoders, - } -} - -// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal -func (iter *Iterator) ReadVal(obj interface{}) { - depth := iter.depth - cacheKey := reflect2.RTypeOf(obj) - decoder := iter.cfg.getDecoderFromCache(cacheKey) - if decoder == nil { - typ := reflect2.TypeOf(obj) - if typ.Kind() != reflect.Ptr { - iter.ReportError("ReadVal", "can only unmarshal into pointer") - return - } - decoder = iter.cfg.DecoderOf(typ) - } - ptr := reflect2.PtrOf(obj) - if ptr == nil { - iter.ReportError("ReadVal", "can not read into nil pointer") - return - } - decoder.Decode(ptr, iter) - if iter.depth != depth { - iter.ReportError("ReadVal", "unexpected mismatched nesting") - return - } -} - -// WriteVal copy the go interface into underlying JSON, same as json.Marshal -func (stream *Stream) WriteVal(val interface{}) { - if nil == val { - stream.WriteNil() - return - } - cacheKey := reflect2.RTypeOf(val) - encoder := stream.cfg.getEncoderFromCache(cacheKey) - if encoder == nil { - typ := reflect2.TypeOf(val) - encoder = stream.cfg.EncoderOf(typ) - } - encoder.Encode(reflect2.PtrOf(val), stream) -} - -func (cfg *frozenConfig) DecoderOf(typ reflect2.Type) ValDecoder { - cacheKey := typ.RType() - decoder := cfg.getDecoderFromCache(cacheKey) - if decoder != nil { - return decoder - } - ctx := &ctx{ - frozenConfig: cfg, - prefix: "", - decoders: map[reflect2.Type]ValDecoder{}, - encoders: map[reflect2.Type]ValEncoder{}, - } - ptrType := typ.(*reflect2.UnsafePtrType) - decoder = decoderOfType(ctx, ptrType.Elem()) - cfg.addDecoderToCache(cacheKey, decoder) - return decoder -} - -func decoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := getTypeDecoderFromExtension(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfType(ctx, typ) - for _, extension := range extensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder) - for _, extension := range ctx.extraExtensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - return decoder -} - -func createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := ctx.decoders[typ] - if decoder != nil { - return decoder - } - placeholder := &placeholderDecoder{} - ctx.decoders[typ] = placeholder - decoder = _createDecoderOfType(ctx, typ) - placeholder.decoder = decoder - return decoder -} - -func _createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := createDecoderOfJsonRawMessage(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfJsonNumber(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfMarshaler(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfAny(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfNative(ctx, typ) - if decoder != nil { - return decoder - } - switch typ.Kind() { - case reflect.Interface: - ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType) - if isIFace { - return &ifaceDecoder{valType: ifaceType} - } - return &efaceDecoder{} - case reflect.Struct: - return decoderOfStruct(ctx, typ) - case reflect.Array: - return decoderOfArray(ctx, typ) - case reflect.Slice: - return decoderOfSlice(ctx, typ) - case reflect.Map: - return decoderOfMap(ctx, typ) - case reflect.Ptr: - return decoderOfOptional(ctx, typ) - default: - return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} - } -} - -func (cfg *frozenConfig) EncoderOf(typ reflect2.Type) ValEncoder { - cacheKey := typ.RType() - encoder := cfg.getEncoderFromCache(cacheKey) - if encoder != nil { - return encoder - } - ctx := &ctx{ - frozenConfig: cfg, - prefix: "", - decoders: map[reflect2.Type]ValDecoder{}, - encoders: map[reflect2.Type]ValEncoder{}, - } - encoder = encoderOfType(ctx, typ) - if typ.LikePtr() { - encoder = &onePtrEncoder{encoder} - } - cfg.addEncoderToCache(cacheKey, encoder) - return encoder -} - -type onePtrEncoder struct { - encoder ValEncoder -} - -func (encoder *onePtrEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) -} - -func (encoder *onePtrEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) -} - -func encoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := getTypeEncoderFromExtension(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfType(ctx, typ) - for _, extension := range extensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder) - for _, extension := range ctx.extraExtensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - return encoder -} - -func createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := ctx.encoders[typ] - if encoder != nil { - return encoder - } - placeholder := &placeholderEncoder{} - ctx.encoders[typ] = placeholder - encoder = _createEncoderOfType(ctx, typ) - placeholder.encoder = encoder - return encoder -} -func _createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := createEncoderOfJsonRawMessage(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfJsonNumber(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfMarshaler(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfAny(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfNative(ctx, typ) - if encoder != nil { - return encoder - } - kind := typ.Kind() - switch kind { - case reflect.Interface: - return &dynamicEncoder{typ} - case reflect.Struct: - return encoderOfStruct(ctx, typ) - case reflect.Array: - return encoderOfArray(ctx, typ) - case reflect.Slice: - return encoderOfSlice(ctx, typ) - case reflect.Map: - return encoderOfMap(ctx, typ) - case reflect.Ptr: - return encoderOfOptional(ctx, typ) - default: - return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} - } -} - -type lazyErrorDecoder struct { - err error -} - -func (decoder *lazyErrorDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.WhatIsNext() != NilValue { - if iter.Error == nil { - iter.Error = decoder.err - } - } else { - iter.Skip() - } -} - -type lazyErrorEncoder struct { - err error -} - -func (encoder *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if ptr == nil { - stream.WriteNil() - } else if stream.Error == nil { - stream.Error = encoder.err - } -} - -func (encoder *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type placeholderDecoder struct { - decoder ValDecoder -} - -func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.decoder.Decode(ptr, iter) -} - -type placeholderEncoder struct { - encoder ValEncoder -} - -func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.encoder.Encode(ptr, stream) -} - -func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.encoder.IsEmpty(ptr) -} diff --git a/vendor/github.com/json-iterator/go/reflect_array.go b/vendor/github.com/json-iterator/go/reflect_array.go deleted file mode 100644 index 13a0b7b..0000000 --- a/vendor/github.com/json-iterator/go/reflect_array.go +++ /dev/null @@ -1,104 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "unsafe" -) - -func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { - arrayType := typ.(*reflect2.UnsafeArrayType) - decoder := decoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) - return &arrayDecoder{arrayType, decoder} -} - -func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder { - arrayType := typ.(*reflect2.UnsafeArrayType) - if arrayType.Len() == 0 { - return emptyArrayEncoder{} - } - encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) - return &arrayEncoder{arrayType, encoder} -} - -type emptyArrayEncoder struct{} - -func (encoder emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteEmptyArray() -} - -func (encoder emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return true -} - -type arrayEncoder struct { - arrayType *reflect2.UnsafeArrayType - elemEncoder ValEncoder -} - -func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteArrayStart() - elemPtr := unsafe.Pointer(ptr) - encoder.elemEncoder.Encode(elemPtr, stream) - for i := 1; i < encoder.arrayType.Len(); i++ { - stream.WriteMore() - elemPtr = encoder.arrayType.UnsafeGetIndex(ptr, i) - encoder.elemEncoder.Encode(elemPtr, stream) - } - stream.WriteArrayEnd() - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error()) - } -} - -func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type arrayDecoder struct { - arrayType *reflect2.UnsafeArrayType - elemDecoder ValDecoder -} - -func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.doDecode(ptr, iter) - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error()) - } -} - -func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - arrayType := decoder.arrayType - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return - } - if c != '[' { - iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c})) - return - } - c = iter.nextToken() - if c == ']' { - return - } - iter.unreadByte() - elemPtr := arrayType.UnsafeGetIndex(ptr, 0) - decoder.elemDecoder.Decode(elemPtr, iter) - length := 1 - for c = iter.nextToken(); c == ','; c = iter.nextToken() { - if length >= arrayType.Len() { - iter.Skip() - continue - } - idx := length - length += 1 - elemPtr = arrayType.UnsafeGetIndex(ptr, idx) - decoder.elemDecoder.Decode(elemPtr, iter) - } - if c != ']' { - iter.ReportError("decode array", "expect ], but found "+string([]byte{c})) - return - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_dynamic.go b/vendor/github.com/json-iterator/go/reflect_dynamic.go deleted file mode 100644 index 8b6bc8b..0000000 --- a/vendor/github.com/json-iterator/go/reflect_dynamic.go +++ /dev/null @@ -1,70 +0,0 @@ -package jsoniter - -import ( - "github.com/modern-go/reflect2" - "reflect" - "unsafe" -) - -type dynamicEncoder struct { - valType reflect2.Type -} - -func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - stream.WriteVal(obj) -} - -func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.valType.UnsafeIndirect(ptr) == nil -} - -type efaceDecoder struct { -} - -func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - pObj := (*interface{})(ptr) - obj := *pObj - if obj == nil { - *pObj = iter.Read() - return - } - typ := reflect2.TypeOf(obj) - if typ.Kind() != reflect.Ptr { - *pObj = iter.Read() - return - } - ptrType := typ.(*reflect2.UnsafePtrType) - ptrElemType := ptrType.Elem() - if iter.WhatIsNext() == NilValue { - if ptrElemType.Kind() != reflect.Ptr { - iter.skipFourBytes('n', 'u', 'l', 'l') - *pObj = nil - return - } - } - if reflect2.IsNil(obj) { - obj := ptrElemType.New() - iter.ReadVal(obj) - *pObj = obj - return - } - iter.ReadVal(obj) -} - -type ifaceDecoder struct { - valType *reflect2.UnsafeIFaceType -} - -func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew()) - return - } - obj := decoder.valType.UnsafeIndirect(ptr) - if reflect2.IsNil(obj) { - iter.ReportError("decode non empty interface", "can not unmarshal into nil") - return - } - iter.ReadVal(obj) -} diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go deleted file mode 100644 index 74a97bf..0000000 --- a/vendor/github.com/json-iterator/go/reflect_extension.go +++ /dev/null @@ -1,483 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "reflect" - "sort" - "strings" - "unicode" - "unsafe" -) - -var typeDecoders = map[string]ValDecoder{} -var fieldDecoders = map[string]ValDecoder{} -var typeEncoders = map[string]ValEncoder{} -var fieldEncoders = map[string]ValEncoder{} -var extensions = []Extension{} - -// StructDescriptor describe how should we encode/decode the struct -type StructDescriptor struct { - Type reflect2.Type - Fields []*Binding -} - -// GetField get one field from the descriptor by its name. -// Can not use map here to keep field orders. -func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding { - for _, binding := range structDescriptor.Fields { - if binding.Field.Name() == fieldName { - return binding - } - } - return nil -} - -// Binding describe how should we encode/decode the struct field -type Binding struct { - levels []int - Field reflect2.StructField - FromNames []string - ToNames []string - Encoder ValEncoder - Decoder ValDecoder -} - -// Extension the one for all SPI. Customize encoding/decoding by specifying alternate encoder/decoder. -// Can also rename fields by UpdateStructDescriptor. -type Extension interface { - UpdateStructDescriptor(structDescriptor *StructDescriptor) - CreateMapKeyDecoder(typ reflect2.Type) ValDecoder - CreateMapKeyEncoder(typ reflect2.Type) ValEncoder - CreateDecoder(typ reflect2.Type) ValDecoder - CreateEncoder(typ reflect2.Type) ValEncoder - DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder - DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder -} - -// DummyExtension embed this type get dummy implementation for all methods of Extension -type DummyExtension struct { -} - -// UpdateStructDescriptor No-op -func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { -} - -// CreateMapKeyDecoder No-op -func (extension *DummyExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateMapKeyEncoder No-op -func (extension *DummyExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// CreateDecoder No-op -func (extension *DummyExtension) CreateDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateEncoder No-op -func (extension *DummyExtension) CreateEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// DecorateDecoder No-op -func (extension *DummyExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { - return decoder -} - -// DecorateEncoder No-op -func (extension *DummyExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { - return encoder -} - -type EncoderExtension map[reflect2.Type]ValEncoder - -// UpdateStructDescriptor No-op -func (extension EncoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { -} - -// CreateDecoder No-op -func (extension EncoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateEncoder get encoder from map -func (extension EncoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { - return extension[typ] -} - -// CreateMapKeyDecoder No-op -func (extension EncoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateMapKeyEncoder No-op -func (extension EncoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// DecorateDecoder No-op -func (extension EncoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { - return decoder -} - -// DecorateEncoder No-op -func (extension EncoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { - return encoder -} - -type DecoderExtension map[reflect2.Type]ValDecoder - -// UpdateStructDescriptor No-op -func (extension DecoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { -} - -// CreateMapKeyDecoder No-op -func (extension DecoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateMapKeyEncoder No-op -func (extension DecoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// CreateDecoder get decoder from map -func (extension DecoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { - return extension[typ] -} - -// CreateEncoder No-op -func (extension DecoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// DecorateDecoder No-op -func (extension DecoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { - return decoder -} - -// DecorateEncoder No-op -func (extension DecoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { - return encoder -} - -type funcDecoder struct { - fun DecoderFunc -} - -func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.fun(ptr, iter) -} - -type funcEncoder struct { - fun EncoderFunc - isEmptyFunc func(ptr unsafe.Pointer) bool -} - -func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.fun(ptr, stream) -} - -func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { - if encoder.isEmptyFunc == nil { - return false - } - return encoder.isEmptyFunc(ptr) -} - -// DecoderFunc the function form of TypeDecoder -type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) - -// EncoderFunc the function form of TypeEncoder -type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) - -// RegisterTypeDecoderFunc register TypeDecoder for a type with function -func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { - typeDecoders[typ] = &funcDecoder{fun} -} - -// RegisterTypeDecoder register TypeDecoder for a typ -func RegisterTypeDecoder(typ string, decoder ValDecoder) { - typeDecoders[typ] = decoder -} - -// RegisterFieldDecoderFunc register TypeDecoder for a struct field with function -func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) { - RegisterFieldDecoder(typ, field, &funcDecoder{fun}) -} - -// RegisterFieldDecoder register TypeDecoder for a struct field -func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) { - fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder -} - -// RegisterTypeEncoderFunc register TypeEncoder for a type with encode/isEmpty function -func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { - typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc} -} - -// RegisterTypeEncoder register TypeEncoder for a type -func RegisterTypeEncoder(typ string, encoder ValEncoder) { - typeEncoders[typ] = encoder -} - -// RegisterFieldEncoderFunc register TypeEncoder for a struct field with encode/isEmpty function -func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { - RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc}) -} - -// RegisterFieldEncoder register TypeEncoder for a struct field -func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { - fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder -} - -// RegisterExtension register extension -func RegisterExtension(extension Extension) { - extensions = append(extensions, extension) -} - -func getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := _getTypeDecoderFromExtension(ctx, typ) - if decoder != nil { - for _, extension := range extensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder) - for _, extension := range ctx.extraExtensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - } - return decoder -} -func _getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { - for _, extension := range extensions { - decoder := extension.CreateDecoder(typ) - if decoder != nil { - return decoder - } - } - decoder := ctx.decoderExtension.CreateDecoder(typ) - if decoder != nil { - return decoder - } - for _, extension := range ctx.extraExtensions { - decoder := extension.CreateDecoder(typ) - if decoder != nil { - return decoder - } - } - typeName := typ.String() - decoder = typeDecoders[typeName] - if decoder != nil { - return decoder - } - if typ.Kind() == reflect.Ptr { - ptrType := typ.(*reflect2.UnsafePtrType) - decoder := typeDecoders[ptrType.Elem().String()] - if decoder != nil { - return &OptionalDecoder{ptrType.Elem(), decoder} - } - } - return nil -} - -func getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := _getTypeEncoderFromExtension(ctx, typ) - if encoder != nil { - for _, extension := range extensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder) - for _, extension := range ctx.extraExtensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - } - return encoder -} - -func _getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { - for _, extension := range extensions { - encoder := extension.CreateEncoder(typ) - if encoder != nil { - return encoder - } - } - encoder := ctx.encoderExtension.CreateEncoder(typ) - if encoder != nil { - return encoder - } - for _, extension := range ctx.extraExtensions { - encoder := extension.CreateEncoder(typ) - if encoder != nil { - return encoder - } - } - typeName := typ.String() - encoder = typeEncoders[typeName] - if encoder != nil { - return encoder - } - if typ.Kind() == reflect.Ptr { - typePtr := typ.(*reflect2.UnsafePtrType) - encoder := typeEncoders[typePtr.Elem().String()] - if encoder != nil { - return &OptionalEncoder{encoder} - } - } - return nil -} - -func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { - structType := typ.(*reflect2.UnsafeStructType) - embeddedBindings := []*Binding{} - bindings := []*Binding{} - for i := 0; i < structType.NumField(); i++ { - field := structType.Field(i) - tag, hastag := field.Tag().Lookup(ctx.getTagKey()) - if ctx.onlyTaggedField && !hastag && !field.Anonymous() { - continue - } - if tag == "-" || field.Name() == "_" { - continue - } - tagParts := strings.Split(tag, ",") - if field.Anonymous() && (tag == "" || tagParts[0] == "") { - if field.Type().Kind() == reflect.Struct { - structDescriptor := describeStruct(ctx, field.Type()) - for _, binding := range structDescriptor.Fields { - binding.levels = append([]int{i}, binding.levels...) - omitempty := binding.Encoder.(*structFieldEncoder).omitempty - binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} - binding.Decoder = &structFieldDecoder{field, binding.Decoder} - embeddedBindings = append(embeddedBindings, binding) - } - continue - } else if field.Type().Kind() == reflect.Ptr { - ptrType := field.Type().(*reflect2.UnsafePtrType) - if ptrType.Elem().Kind() == reflect.Struct { - structDescriptor := describeStruct(ctx, ptrType.Elem()) - for _, binding := range structDescriptor.Fields { - binding.levels = append([]int{i}, binding.levels...) - omitempty := binding.Encoder.(*structFieldEncoder).omitempty - binding.Encoder = &dereferenceEncoder{binding.Encoder} - binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} - binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} - binding.Decoder = &structFieldDecoder{field, binding.Decoder} - embeddedBindings = append(embeddedBindings, binding) - } - continue - } - } - } - fieldNames := calcFieldNames(field.Name(), tagParts[0], tag) - fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name()) - decoder := fieldDecoders[fieldCacheKey] - if decoder == nil { - decoder = decoderOfType(ctx.append(field.Name()), field.Type()) - } - encoder := fieldEncoders[fieldCacheKey] - if encoder == nil { - encoder = encoderOfType(ctx.append(field.Name()), field.Type()) - } - binding := &Binding{ - Field: field, - FromNames: fieldNames, - ToNames: fieldNames, - Decoder: decoder, - Encoder: encoder, - } - binding.levels = []int{i} - bindings = append(bindings, binding) - } - return createStructDescriptor(ctx, typ, bindings, embeddedBindings) -} -func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { - structDescriptor := &StructDescriptor{ - Type: typ, - Fields: bindings, - } - for _, extension := range extensions { - extension.UpdateStructDescriptor(structDescriptor) - } - ctx.encoderExtension.UpdateStructDescriptor(structDescriptor) - ctx.decoderExtension.UpdateStructDescriptor(structDescriptor) - for _, extension := range ctx.extraExtensions { - extension.UpdateStructDescriptor(structDescriptor) - } - processTags(structDescriptor, ctx.frozenConfig) - // merge normal & embedded bindings & sort with original order - allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) - sort.Sort(allBindings) - structDescriptor.Fields = allBindings - return structDescriptor -} - -type sortableBindings []*Binding - -func (bindings sortableBindings) Len() int { - return len(bindings) -} - -func (bindings sortableBindings) Less(i, j int) bool { - left := bindings[i].levels - right := bindings[j].levels - k := 0 - for { - if left[k] < right[k] { - return true - } else if left[k] > right[k] { - return false - } - k++ - } -} - -func (bindings sortableBindings) Swap(i, j int) { - bindings[i], bindings[j] = bindings[j], bindings[i] -} - -func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) { - for _, binding := range structDescriptor.Fields { - shouldOmitEmpty := false - tagParts := strings.Split(binding.Field.Tag().Get(cfg.getTagKey()), ",") - for _, tagPart := range tagParts[1:] { - if tagPart == "omitempty" { - shouldOmitEmpty = true - } else if tagPart == "string" { - if binding.Field.Type().Kind() == reflect.String { - binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg} - binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg} - } else { - binding.Decoder = &stringModeNumberDecoder{binding.Decoder} - binding.Encoder = &stringModeNumberEncoder{binding.Encoder} - } - } - } - binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} - binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} - } -} - -func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { - // ignore? - if wholeTag == "-" { - return []string{} - } - // rename? - var fieldNames []string - if tagProvidedFieldName == "" { - fieldNames = []string{originalFieldName} - } else { - fieldNames = []string{tagProvidedFieldName} - } - // private? - isNotExported := unicode.IsLower(rune(originalFieldName[0])) || originalFieldName[0] == '_' - if isNotExported { - fieldNames = []string{} - } - return fieldNames -} diff --git a/vendor/github.com/json-iterator/go/reflect_json_number.go b/vendor/github.com/json-iterator/go/reflect_json_number.go deleted file mode 100644 index 98d45c1..0000000 --- a/vendor/github.com/json-iterator/go/reflect_json_number.go +++ /dev/null @@ -1,112 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "github.com/modern-go/reflect2" - "strconv" - "unsafe" -) - -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { - return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { - return strconv.ParseInt(string(n), 10, 64) -} - -func CastJsonNumber(val interface{}) (string, bool) { - switch typedVal := val.(type) { - case json.Number: - return string(typedVal), true - case Number: - return string(typedVal), true - } - return "", false -} - -var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem() -var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem() - -func createDecoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ.AssignableTo(jsonNumberType) { - return &jsonNumberCodec{} - } - if typ.AssignableTo(jsoniterNumberType) { - return &jsoniterNumberCodec{} - } - return nil -} - -func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ.AssignableTo(jsonNumberType) { - return &jsonNumberCodec{} - } - if typ.AssignableTo(jsoniterNumberType) { - return &jsoniterNumberCodec{} - } - return nil -} - -type jsonNumberCodec struct { -} - -func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - switch iter.WhatIsNext() { - case StringValue: - *((*json.Number)(ptr)) = json.Number(iter.ReadString()) - case NilValue: - iter.skipFourBytes('n', 'u', 'l', 'l') - *((*json.Number)(ptr)) = "" - default: - *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) - } -} - -func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - number := *((*json.Number)(ptr)) - if len(number) == 0 { - stream.writeByte('0') - } else { - stream.WriteRaw(string(number)) - } -} - -func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*json.Number)(ptr))) == 0 -} - -type jsoniterNumberCodec struct { -} - -func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - switch iter.WhatIsNext() { - case StringValue: - *((*Number)(ptr)) = Number(iter.ReadString()) - case NilValue: - iter.skipFourBytes('n', 'u', 'l', 'l') - *((*Number)(ptr)) = "" - default: - *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) - } -} - -func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - number := *((*Number)(ptr)) - if len(number) == 0 { - stream.writeByte('0') - } else { - stream.WriteRaw(string(number)) - } -} - -func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*Number)(ptr))) == 0 -} diff --git a/vendor/github.com/json-iterator/go/reflect_json_raw_message.go b/vendor/github.com/json-iterator/go/reflect_json_raw_message.go deleted file mode 100644 index f261993..0000000 --- a/vendor/github.com/json-iterator/go/reflect_json_raw_message.go +++ /dev/null @@ -1,60 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "github.com/modern-go/reflect2" - "unsafe" -) - -var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem() -var jsoniterRawMessageType = reflect2.TypeOfPtr((*RawMessage)(nil)).Elem() - -func createEncoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ == jsonRawMessageType { - return &jsonRawMessageCodec{} - } - if typ == jsoniterRawMessageType { - return &jsoniterRawMessageCodec{} - } - return nil -} - -func createDecoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ == jsonRawMessageType { - return &jsonRawMessageCodec{} - } - if typ == jsoniterRawMessageType { - return &jsoniterRawMessageCodec{} - } - return nil -} - -type jsonRawMessageCodec struct { -} - -func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - *((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes()) -} - -func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) -} - -func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*json.RawMessage)(ptr))) == 0 -} - -type jsoniterRawMessageCodec struct { -} - -func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - *((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes()) -} - -func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteRaw(string(*((*RawMessage)(ptr)))) -} - -func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*RawMessage)(ptr))) == 0 -} diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go deleted file mode 100644 index 5829671..0000000 --- a/vendor/github.com/json-iterator/go/reflect_map.go +++ /dev/null @@ -1,346 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "reflect" - "sort" - "unsafe" -) - -func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { - mapType := typ.(*reflect2.UnsafeMapType) - keyDecoder := decoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()) - elemDecoder := decoderOfType(ctx.append("[mapElem]"), mapType.Elem()) - return &mapDecoder{ - mapType: mapType, - keyType: mapType.Key(), - elemType: mapType.Elem(), - keyDecoder: keyDecoder, - elemDecoder: elemDecoder, - } -} - -func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder { - mapType := typ.(*reflect2.UnsafeMapType) - if ctx.sortMapKeys { - return &sortKeysMapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), - } - } - return &mapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), - } -} - -func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := ctx.decoderExtension.CreateMapKeyDecoder(typ) - if decoder != nil { - return decoder - } - for _, extension := range ctx.extraExtensions { - decoder := extension.CreateMapKeyDecoder(typ) - if decoder != nil { - return decoder - } - } - - ptrType := reflect2.PtrTo(typ) - if ptrType.Implements(unmarshalerType) { - return &referenceDecoder{ - &unmarshalerDecoder{ - valType: ptrType, - }, - } - } - if typ.Implements(unmarshalerType) { - return &unmarshalerDecoder{ - valType: typ, - } - } - if ptrType.Implements(textUnmarshalerType) { - return &referenceDecoder{ - &textUnmarshalerDecoder{ - valType: ptrType, - }, - } - } - if typ.Implements(textUnmarshalerType) { - return &textUnmarshalerDecoder{ - valType: typ, - } - } - - switch typ.Kind() { - case reflect.String: - return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) - case reflect.Bool, - reflect.Uint8, reflect.Int8, - reflect.Uint16, reflect.Int16, - reflect.Uint32, reflect.Int32, - reflect.Uint64, reflect.Int64, - reflect.Uint, reflect.Int, - reflect.Float32, reflect.Float64, - reflect.Uintptr: - typ = reflect2.DefaultTypeOfKind(typ.Kind()) - return &numericMapKeyDecoder{decoderOfType(ctx, typ)} - default: - return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} - } -} - -func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := ctx.encoderExtension.CreateMapKeyEncoder(typ) - if encoder != nil { - return encoder - } - for _, extension := range ctx.extraExtensions { - encoder := extension.CreateMapKeyEncoder(typ) - if encoder != nil { - return encoder - } - } - - if typ == textMarshalerType { - return &directTextMarshalerEncoder{ - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - } - if typ.Implements(textMarshalerType) { - return &textMarshalerEncoder{ - valType: typ, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - } - - switch typ.Kind() { - case reflect.String: - return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) - case reflect.Bool, - reflect.Uint8, reflect.Int8, - reflect.Uint16, reflect.Int16, - reflect.Uint32, reflect.Int32, - reflect.Uint64, reflect.Int64, - reflect.Uint, reflect.Int, - reflect.Float32, reflect.Float64, - reflect.Uintptr: - typ = reflect2.DefaultTypeOfKind(typ.Kind()) - return &numericMapKeyEncoder{encoderOfType(ctx, typ)} - default: - if typ.Kind() == reflect.Interface { - return &dynamicMapKeyEncoder{ctx, typ} - } - return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} - } -} - -type mapDecoder struct { - mapType *reflect2.UnsafeMapType - keyType reflect2.Type - elemType reflect2.Type - keyDecoder ValDecoder - elemDecoder ValDecoder -} - -func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - mapType := decoder.mapType - c := iter.nextToken() - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - *(*unsafe.Pointer)(ptr) = nil - mapType.UnsafeSet(ptr, mapType.UnsafeNew()) - return - } - if mapType.UnsafeIsNil(ptr) { - mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0)) - } - if c != '{' { - iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) - return - } - c = iter.nextToken() - if c == '}' { - return - } - iter.unreadByte() - key := decoder.keyType.UnsafeNew() - decoder.keyDecoder.Decode(key, iter) - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - return - } - elem := decoder.elemType.UnsafeNew() - decoder.elemDecoder.Decode(elem, iter) - decoder.mapType.UnsafeSetIndex(ptr, key, elem) - for c = iter.nextToken(); c == ','; c = iter.nextToken() { - key := decoder.keyType.UnsafeNew() - decoder.keyDecoder.Decode(key, iter) - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - return - } - elem := decoder.elemType.UnsafeNew() - decoder.elemDecoder.Decode(elem, iter) - decoder.mapType.UnsafeSetIndex(ptr, key, elem) - } - if c != '}' { - iter.ReportError("ReadMapCB", `expect }, but found `+string([]byte{c})) - } -} - -type numericMapKeyDecoder struct { - decoder ValDecoder -} - -func (decoder *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - if c != '"' { - iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) - return - } - decoder.decoder.Decode(ptr, iter) - c = iter.nextToken() - if c != '"' { - iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) - return - } -} - -type numericMapKeyEncoder struct { - encoder ValEncoder -} - -func (encoder *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.writeByte('"') - encoder.encoder.Encode(ptr, stream) - stream.writeByte('"') -} - -func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type dynamicMapKeyEncoder struct { - ctx *ctx - valType reflect2.Type -} - -func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) -} - -func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { - obj := encoder.valType.UnsafeIndirect(ptr) - return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) -} - -type mapEncoder struct { - mapType *reflect2.UnsafeMapType - keyEncoder ValEncoder - elemEncoder ValEncoder -} - -func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *(*unsafe.Pointer)(ptr) == nil { - stream.WriteNil() - return - } - stream.WriteObjectStart() - iter := encoder.mapType.UnsafeIterate(ptr) - for i := 0; iter.HasNext(); i++ { - if i != 0 { - stream.WriteMore() - } - key, elem := iter.UnsafeNext() - encoder.keyEncoder.Encode(key, stream) - if stream.indention > 0 { - stream.writeTwoBytes(byte(':'), byte(' ')) - } else { - stream.writeByte(':') - } - encoder.elemEncoder.Encode(elem, stream) - } - stream.WriteObjectEnd() -} - -func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { - iter := encoder.mapType.UnsafeIterate(ptr) - return !iter.HasNext() -} - -type sortKeysMapEncoder struct { - mapType *reflect2.UnsafeMapType - keyEncoder ValEncoder - elemEncoder ValEncoder -} - -func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *(*unsafe.Pointer)(ptr) == nil { - stream.WriteNil() - return - } - stream.WriteObjectStart() - mapIter := encoder.mapType.UnsafeIterate(ptr) - subStream := stream.cfg.BorrowStream(nil) - subStream.Attachment = stream.Attachment - subIter := stream.cfg.BorrowIterator(nil) - keyValues := encodedKeyValues{} - for mapIter.HasNext() { - key, elem := mapIter.UnsafeNext() - subStreamIndex := subStream.Buffered() - encoder.keyEncoder.Encode(key, subStream) - if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { - stream.Error = subStream.Error - } - encodedKey := subStream.Buffer()[subStreamIndex:] - subIter.ResetBytes(encodedKey) - decodedKey := subIter.ReadString() - if stream.indention > 0 { - subStream.writeTwoBytes(byte(':'), byte(' ')) - } else { - subStream.writeByte(':') - } - encoder.elemEncoder.Encode(elem, subStream) - keyValues = append(keyValues, encodedKV{ - key: decodedKey, - keyValue: subStream.Buffer()[subStreamIndex:], - }) - } - sort.Sort(keyValues) - for i, keyValue := range keyValues { - if i != 0 { - stream.WriteMore() - } - stream.Write(keyValue.keyValue) - } - if subStream.Error != nil && stream.Error == nil { - stream.Error = subStream.Error - } - stream.WriteObjectEnd() - stream.cfg.ReturnStream(subStream) - stream.cfg.ReturnIterator(subIter) -} - -func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { - iter := encoder.mapType.UnsafeIterate(ptr) - return !iter.HasNext() -} - -type encodedKeyValues []encodedKV - -type encodedKV struct { - key string - keyValue []byte -} - -func (sv encodedKeyValues) Len() int { return len(sv) } -func (sv encodedKeyValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } -func (sv encodedKeyValues) Less(i, j int) bool { return sv[i].key < sv[j].key } diff --git a/vendor/github.com/json-iterator/go/reflect_marshaler.go b/vendor/github.com/json-iterator/go/reflect_marshaler.go deleted file mode 100644 index 3e21f37..0000000 --- a/vendor/github.com/json-iterator/go/reflect_marshaler.go +++ /dev/null @@ -1,225 +0,0 @@ -package jsoniter - -import ( - "encoding" - "encoding/json" - "unsafe" - - "github.com/modern-go/reflect2" -) - -var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() -var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem() -var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem() -var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem() - -func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder { - ptrType := reflect2.PtrTo(typ) - if ptrType.Implements(unmarshalerType) { - return &referenceDecoder{ - &unmarshalerDecoder{ptrType}, - } - } - if ptrType.Implements(textUnmarshalerType) { - return &referenceDecoder{ - &textUnmarshalerDecoder{ptrType}, - } - } - return nil -} - -func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ == marshalerType { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &directMarshalerEncoder{ - checkIsEmpty: checkIsEmpty, - } - return encoder - } - if typ.Implements(marshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &marshalerEncoder{ - valType: typ, - checkIsEmpty: checkIsEmpty, - } - return encoder - } - ptrType := reflect2.PtrTo(typ) - if ctx.prefix != "" && ptrType.Implements(marshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, ptrType) - var encoder ValEncoder = &marshalerEncoder{ - valType: ptrType, - checkIsEmpty: checkIsEmpty, - } - return &referenceEncoder{encoder} - } - if typ == textMarshalerType { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &directTextMarshalerEncoder{ - checkIsEmpty: checkIsEmpty, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - return encoder - } - if typ.Implements(textMarshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &textMarshalerEncoder{ - valType: typ, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - checkIsEmpty: checkIsEmpty, - } - return encoder - } - // if prefix is empty, the type is the root type - if ctx.prefix != "" && ptrType.Implements(textMarshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, ptrType) - var encoder ValEncoder = &textMarshalerEncoder{ - valType: ptrType, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - checkIsEmpty: checkIsEmpty, - } - return &referenceEncoder{encoder} - } - return nil -} - -type marshalerEncoder struct { - checkIsEmpty checkIsEmpty - valType reflect2.Type -} - -func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - if encoder.valType.IsNullable() && reflect2.IsNil(obj) { - stream.WriteNil() - return - } - marshaler := obj.(json.Marshaler) - bytes, err := marshaler.MarshalJSON() - if err != nil { - stream.Error = err - } else { - // html escape was already done by jsoniter - // but the extra '\n' should be trimed - l := len(bytes) - if l > 0 && bytes[l-1] == '\n' { - bytes = bytes[:l-1] - } - stream.Write(bytes) - } -} - -func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type directMarshalerEncoder struct { - checkIsEmpty checkIsEmpty -} - -func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - marshaler := *(*json.Marshaler)(ptr) - if marshaler == nil { - stream.WriteNil() - return - } - bytes, err := marshaler.MarshalJSON() - if err != nil { - stream.Error = err - } else { - stream.Write(bytes) - } -} - -func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type textMarshalerEncoder struct { - valType reflect2.Type - stringEncoder ValEncoder - checkIsEmpty checkIsEmpty -} - -func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - if encoder.valType.IsNullable() && reflect2.IsNil(obj) { - stream.WriteNil() - return - } - marshaler := (obj).(encoding.TextMarshaler) - bytes, err := marshaler.MarshalText() - if err != nil { - stream.Error = err - } else { - str := string(bytes) - encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) - } -} - -func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type directTextMarshalerEncoder struct { - stringEncoder ValEncoder - checkIsEmpty checkIsEmpty -} - -func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - marshaler := *(*encoding.TextMarshaler)(ptr) - if marshaler == nil { - stream.WriteNil() - return - } - bytes, err := marshaler.MarshalText() - if err != nil { - stream.Error = err - } else { - str := string(bytes) - encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) - } -} - -func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type unmarshalerDecoder struct { - valType reflect2.Type -} - -func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - valType := decoder.valType - obj := valType.UnsafeIndirect(ptr) - unmarshaler := obj.(json.Unmarshaler) - iter.nextToken() - iter.unreadByte() // skip spaces - bytes := iter.SkipAndReturnBytes() - err := unmarshaler.UnmarshalJSON(bytes) - if err != nil { - iter.ReportError("unmarshalerDecoder", err.Error()) - } -} - -type textUnmarshalerDecoder struct { - valType reflect2.Type -} - -func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - valType := decoder.valType - obj := valType.UnsafeIndirect(ptr) - if reflect2.IsNil(obj) { - ptrType := valType.(*reflect2.UnsafePtrType) - elemType := ptrType.Elem() - elem := elemType.UnsafeNew() - ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem)) - obj = valType.UnsafeIndirect(ptr) - } - unmarshaler := (obj).(encoding.TextUnmarshaler) - str := iter.ReadString() - err := unmarshaler.UnmarshalText([]byte(str)) - if err != nil { - iter.ReportError("textUnmarshalerDecoder", err.Error()) - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_native.go b/vendor/github.com/json-iterator/go/reflect_native.go deleted file mode 100644 index f88722d..0000000 --- a/vendor/github.com/json-iterator/go/reflect_native.go +++ /dev/null @@ -1,453 +0,0 @@ -package jsoniter - -import ( - "encoding/base64" - "reflect" - "strconv" - "unsafe" - - "github.com/modern-go/reflect2" -) - -const ptrSize = 32 << uintptr(^uintptr(0)>>63) - -func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { - sliceDecoder := decoderOfSlice(ctx, typ) - return &base64Codec{sliceDecoder: sliceDecoder} - } - typeName := typ.String() - kind := typ.Kind() - switch kind { - case reflect.String: - if typeName != "string" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) - } - return &stringCodec{} - case reflect.Int: - if typeName != "int" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &int32Codec{} - } - return &int64Codec{} - case reflect.Int8: - if typeName != "int8" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) - } - return &int8Codec{} - case reflect.Int16: - if typeName != "int16" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) - } - return &int16Codec{} - case reflect.Int32: - if typeName != "int32" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) - } - return &int32Codec{} - case reflect.Int64: - if typeName != "int64" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) - } - return &int64Codec{} - case reflect.Uint: - if typeName != "uint" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint8: - if typeName != "uint8" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) - } - return &uint8Codec{} - case reflect.Uint16: - if typeName != "uint16" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) - } - return &uint16Codec{} - case reflect.Uint32: - if typeName != "uint32" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) - } - return &uint32Codec{} - case reflect.Uintptr: - if typeName != "uintptr" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) - } - if ptrSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint64: - if typeName != "uint64" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) - } - return &uint64Codec{} - case reflect.Float32: - if typeName != "float32" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) - } - return &float32Codec{} - case reflect.Float64: - if typeName != "float64" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) - } - return &float64Codec{} - case reflect.Bool: - if typeName != "bool" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) - } - return &boolCodec{} - } - return nil -} - -func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { - sliceDecoder := decoderOfSlice(ctx, typ) - return &base64Codec{sliceDecoder: sliceDecoder} - } - typeName := typ.String() - switch typ.Kind() { - case reflect.String: - if typeName != "string" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) - } - return &stringCodec{} - case reflect.Int: - if typeName != "int" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &int32Codec{} - } - return &int64Codec{} - case reflect.Int8: - if typeName != "int8" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) - } - return &int8Codec{} - case reflect.Int16: - if typeName != "int16" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) - } - return &int16Codec{} - case reflect.Int32: - if typeName != "int32" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) - } - return &int32Codec{} - case reflect.Int64: - if typeName != "int64" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) - } - return &int64Codec{} - case reflect.Uint: - if typeName != "uint" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint8: - if typeName != "uint8" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) - } - return &uint8Codec{} - case reflect.Uint16: - if typeName != "uint16" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) - } - return &uint16Codec{} - case reflect.Uint32: - if typeName != "uint32" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) - } - return &uint32Codec{} - case reflect.Uintptr: - if typeName != "uintptr" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) - } - if ptrSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint64: - if typeName != "uint64" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) - } - return &uint64Codec{} - case reflect.Float32: - if typeName != "float32" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) - } - return &float32Codec{} - case reflect.Float64: - if typeName != "float64" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) - } - return &float64Codec{} - case reflect.Bool: - if typeName != "bool" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) - } - return &boolCodec{} - } - return nil -} - -type stringCodec struct { -} - -func (codec *stringCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - *((*string)(ptr)) = iter.ReadString() -} - -func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - str := *((*string)(ptr)) - stream.WriteString(str) -} - -func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*string)(ptr)) == "" -} - -type int8Codec struct { -} - -func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int8)(ptr)) = iter.ReadInt8() - } -} - -func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt8(*((*int8)(ptr))) -} - -func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int8)(ptr)) == 0 -} - -type int16Codec struct { -} - -func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int16)(ptr)) = iter.ReadInt16() - } -} - -func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt16(*((*int16)(ptr))) -} - -func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int16)(ptr)) == 0 -} - -type int32Codec struct { -} - -func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int32)(ptr)) = iter.ReadInt32() - } -} - -func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt32(*((*int32)(ptr))) -} - -func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int32)(ptr)) == 0 -} - -type int64Codec struct { -} - -func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int64)(ptr)) = iter.ReadInt64() - } -} - -func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt64(*((*int64)(ptr))) -} - -func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int64)(ptr)) == 0 -} - -type uint8Codec struct { -} - -func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint8)(ptr)) = iter.ReadUint8() - } -} - -func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint8(*((*uint8)(ptr))) -} - -func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint8)(ptr)) == 0 -} - -type uint16Codec struct { -} - -func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint16)(ptr)) = iter.ReadUint16() - } -} - -func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint16(*((*uint16)(ptr))) -} - -func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint16)(ptr)) == 0 -} - -type uint32Codec struct { -} - -func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint32)(ptr)) = iter.ReadUint32() - } -} - -func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint32(*((*uint32)(ptr))) -} - -func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint32)(ptr)) == 0 -} - -type uint64Codec struct { -} - -func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint64)(ptr)) = iter.ReadUint64() - } -} - -func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint64(*((*uint64)(ptr))) -} - -func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint64)(ptr)) == 0 -} - -type float32Codec struct { -} - -func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*float32)(ptr)) = iter.ReadFloat32() - } -} - -func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat32(*((*float32)(ptr))) -} - -func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float32)(ptr)) == 0 -} - -type float64Codec struct { -} - -func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*float64)(ptr)) = iter.ReadFloat64() - } -} - -func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat64(*((*float64)(ptr))) -} - -func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float64)(ptr)) == 0 -} - -type boolCodec struct { -} - -func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*bool)(ptr)) = iter.ReadBool() - } -} - -func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteBool(*((*bool)(ptr))) -} - -func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { - return !(*((*bool)(ptr))) -} - -type base64Codec struct { - sliceType *reflect2.UnsafeSliceType - sliceDecoder ValDecoder -} - -func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - codec.sliceType.UnsafeSetNil(ptr) - return - } - switch iter.WhatIsNext() { - case StringValue: - src := iter.ReadString() - dst, err := base64.StdEncoding.DecodeString(src) - if err != nil { - iter.ReportError("decode base64", err.Error()) - } else { - codec.sliceType.UnsafeSet(ptr, unsafe.Pointer(&dst)) - } - case ArrayValue: - codec.sliceDecoder.Decode(ptr, iter) - default: - iter.ReportError("base64Codec", "invalid input") - } -} - -func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - if codec.sliceType.UnsafeIsNil(ptr) { - stream.WriteNil() - return - } - src := *((*[]byte)(ptr)) - encoding := base64.StdEncoding - stream.writeByte('"') - if len(src) != 0 { - size := encoding.EncodedLen(len(src)) - buf := make([]byte, size) - encoding.Encode(buf, src) - stream.buf = append(stream.buf, buf...) - } - stream.writeByte('"') -} - -func (codec *base64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*[]byte)(ptr))) == 0 -} diff --git a/vendor/github.com/json-iterator/go/reflect_optional.go b/vendor/github.com/json-iterator/go/reflect_optional.go deleted file mode 100644 index fa71f47..0000000 --- a/vendor/github.com/json-iterator/go/reflect_optional.go +++ /dev/null @@ -1,129 +0,0 @@ -package jsoniter - -import ( - "github.com/modern-go/reflect2" - "unsafe" -) - -func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { - ptrType := typ.(*reflect2.UnsafePtrType) - elemType := ptrType.Elem() - decoder := decoderOfType(ctx, elemType) - return &OptionalDecoder{elemType, decoder} -} - -func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder { - ptrType := typ.(*reflect2.UnsafePtrType) - elemType := ptrType.Elem() - elemEncoder := encoderOfType(ctx, elemType) - encoder := &OptionalEncoder{elemEncoder} - return encoder -} - -type OptionalDecoder struct { - ValueType reflect2.Type - ValueDecoder ValDecoder -} - -func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - *((*unsafe.Pointer)(ptr)) = nil - } else { - if *((*unsafe.Pointer)(ptr)) == nil { - //pointer to null, we have to allocate memory to hold the value - newPtr := decoder.ValueType.UnsafeNew() - decoder.ValueDecoder.Decode(newPtr, iter) - *((*unsafe.Pointer)(ptr)) = newPtr - } else { - //reuse existing instance - decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) - } - } -} - -type dereferenceDecoder struct { - // only to deference a pointer - valueType reflect2.Type - valueDecoder ValDecoder -} - -func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if *((*unsafe.Pointer)(ptr)) == nil { - //pointer to null, we have to allocate memory to hold the value - newPtr := decoder.valueType.UnsafeNew() - decoder.valueDecoder.Decode(newPtr, iter) - *((*unsafe.Pointer)(ptr)) = newPtr - } else { - //reuse existing instance - decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) - } -} - -type OptionalEncoder struct { - ValueEncoder ValEncoder -} - -func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *((*unsafe.Pointer)(ptr)) == nil { - stream.WriteNil() - } else { - encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) - } -} - -func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*unsafe.Pointer)(ptr)) == nil -} - -type dereferenceEncoder struct { - ValueEncoder ValEncoder -} - -func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *((*unsafe.Pointer)(ptr)) == nil { - stream.WriteNil() - } else { - encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) - } -} - -func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { - dePtr := *((*unsafe.Pointer)(ptr)) - if dePtr == nil { - return true - } - return encoder.ValueEncoder.IsEmpty(dePtr) -} - -func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { - deReferenced := *((*unsafe.Pointer)(ptr)) - if deReferenced == nil { - return true - } - isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil) - if !converted { - return false - } - fieldPtr := unsafe.Pointer(deReferenced) - return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) -} - -type referenceEncoder struct { - encoder ValEncoder -} - -func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) -} - -func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) -} - -type referenceDecoder struct { - decoder ValDecoder -} - -func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.decoder.Decode(unsafe.Pointer(&ptr), iter) -} diff --git a/vendor/github.com/json-iterator/go/reflect_slice.go b/vendor/github.com/json-iterator/go/reflect_slice.go deleted file mode 100644 index 9441d79..0000000 --- a/vendor/github.com/json-iterator/go/reflect_slice.go +++ /dev/null @@ -1,99 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "unsafe" -) - -func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { - sliceType := typ.(*reflect2.UnsafeSliceType) - decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) - return &sliceDecoder{sliceType, decoder} -} - -func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder { - sliceType := typ.(*reflect2.UnsafeSliceType) - encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) - return &sliceEncoder{sliceType, encoder} -} - -type sliceEncoder struct { - sliceType *reflect2.UnsafeSliceType - elemEncoder ValEncoder -} - -func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if encoder.sliceType.UnsafeIsNil(ptr) { - stream.WriteNil() - return - } - length := encoder.sliceType.UnsafeLengthOf(ptr) - if length == 0 { - stream.WriteEmptyArray() - return - } - stream.WriteArrayStart() - encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream) - for i := 1; i < length; i++ { - stream.WriteMore() - elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i) - encoder.elemEncoder.Encode(elemPtr, stream) - } - stream.WriteArrayEnd() - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) - } -} - -func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.sliceType.UnsafeLengthOf(ptr) == 0 -} - -type sliceDecoder struct { - sliceType *reflect2.UnsafeSliceType - elemDecoder ValDecoder -} - -func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.doDecode(ptr, iter) - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) - } -} - -func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - sliceType := decoder.sliceType - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - sliceType.UnsafeSetNil(ptr) - return - } - if c != '[' { - iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c})) - return - } - c = iter.nextToken() - if c == ']' { - sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0)) - return - } - iter.unreadByte() - sliceType.UnsafeGrow(ptr, 1) - elemPtr := sliceType.UnsafeGetIndex(ptr, 0) - decoder.elemDecoder.Decode(elemPtr, iter) - length := 1 - for c = iter.nextToken(); c == ','; c = iter.nextToken() { - idx := length - length += 1 - sliceType.UnsafeGrow(ptr, length) - elemPtr = sliceType.UnsafeGetIndex(ptr, idx) - decoder.elemDecoder.Decode(elemPtr, iter) - } - if c != ']' { - iter.ReportError("decode slice", "expect ], but found "+string([]byte{c})) - return - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go deleted file mode 100644 index d7eb0eb..0000000 --- a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go +++ /dev/null @@ -1,1092 +0,0 @@ -package jsoniter - -import ( - "fmt" - "io" - "strings" - "unsafe" - - "github.com/modern-go/reflect2" -) - -func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { - bindings := map[string]*Binding{} - structDescriptor := describeStruct(ctx, typ) - for _, binding := range structDescriptor.Fields { - for _, fromName := range binding.FromNames { - old := bindings[fromName] - if old == nil { - bindings[fromName] = binding - continue - } - ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding) - if ignoreOld { - delete(bindings, fromName) - } - if !ignoreNew { - bindings[fromName] = binding - } - } - } - fields := map[string]*structFieldDecoder{} - for k, binding := range bindings { - fields[k] = binding.Decoder.(*structFieldDecoder) - } - - if !ctx.caseSensitive() { - for k, binding := range bindings { - if _, found := fields[strings.ToLower(k)]; !found { - fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) - } - } - } - - return createStructDecoder(ctx, typ, fields) -} - -func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder { - if ctx.disallowUnknownFields { - return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true} - } - knownHash := map[int64]struct{}{ - 0: {}, - } - - switch len(fields) { - case 0: - return &skipObjectDecoder{typ} - case 1: - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder} - } - case 2: - var fieldHash1 int64 - var fieldHash2 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldHash1 == 0 { - fieldHash1 = fieldHash - fieldDecoder1 = fieldDecoder - } else { - fieldHash2 = fieldHash - fieldDecoder2 = fieldDecoder - } - } - return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2} - case 3: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } - } - return &threeFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3} - case 4: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } - } - return &fourFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4} - case 5: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } - } - return &fiveFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5} - case 6: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } - } - return &sixFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6} - case 7: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } - } - return &sevenFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7} - case 8: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldName8 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else if fieldName7 == 0 { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } else { - fieldName8 = fieldHash - fieldDecoder8 = fieldDecoder - } - } - return &eightFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, - fieldName8, fieldDecoder8} - case 9: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldName8 int64 - var fieldName9 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - var fieldDecoder9 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else if fieldName7 == 0 { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } else if fieldName8 == 0 { - fieldName8 = fieldHash - fieldDecoder8 = fieldDecoder - } else { - fieldName9 = fieldHash - fieldDecoder9 = fieldDecoder - } - } - return &nineFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, - fieldName8, fieldDecoder8, - fieldName9, fieldDecoder9} - case 10: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldName8 int64 - var fieldName9 int64 - var fieldName10 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - var fieldDecoder9 *structFieldDecoder - var fieldDecoder10 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else if fieldName7 == 0 { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } else if fieldName8 == 0 { - fieldName8 = fieldHash - fieldDecoder8 = fieldDecoder - } else if fieldName9 == 0 { - fieldName9 = fieldHash - fieldDecoder9 = fieldDecoder - } else { - fieldName10 = fieldHash - fieldDecoder10 = fieldDecoder - } - } - return &tenFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, - fieldName8, fieldDecoder8, - fieldName9, fieldDecoder9, - fieldName10, fieldDecoder10} - } - return &generalStructDecoder{typ, fields, false} -} - -type generalStructDecoder struct { - typ reflect2.Type - fields map[string]*structFieldDecoder - disallowUnknownFields bool -} - -func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - var c byte - for c = ','; c == ','; c = iter.nextToken() { - decoder.decodeOneField(ptr, iter) - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - if c != '}' { - iter.ReportError("struct Decode", `expect }, but found `+string([]byte{c})) - } - iter.decrementDepth() -} - -func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) { - var field string - var fieldDecoder *structFieldDecoder - if iter.cfg.objectFieldMustBeSimpleString { - fieldBytes := iter.ReadStringAsSlice() - field = *(*string)(unsafe.Pointer(&fieldBytes)) - fieldDecoder = decoder.fields[field] - if fieldDecoder == nil && !iter.cfg.caseSensitive { - fieldDecoder = decoder.fields[strings.ToLower(field)] - } - } else { - field = iter.ReadString() - fieldDecoder = decoder.fields[field] - if fieldDecoder == nil && !iter.cfg.caseSensitive { - fieldDecoder = decoder.fields[strings.ToLower(field)] - } - } - if fieldDecoder == nil { - if decoder.disallowUnknownFields { - msg := "found unknown field: " + field - iter.ReportError("ReadObject", msg) - } - c := iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - iter.Skip() - return - } - c := iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - fieldDecoder.Decode(ptr, iter) -} - -type skipObjectDecoder struct { - typ reflect2.Type -} - -func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - valueType := iter.WhatIsNext() - if valueType != ObjectValue && valueType != NilValue { - iter.ReportError("skipObjectDecoder", "expect object or null") - return - } - iter.Skip() -} - -type oneFieldStructDecoder struct { - typ reflect2.Type - fieldHash int64 - fieldDecoder *structFieldDecoder -} - -func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - if iter.readFieldHash() == decoder.fieldHash { - decoder.fieldDecoder.Decode(ptr, iter) - } else { - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type twoFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder -} - -func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type threeFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder -} - -func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type fourFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder -} - -func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type fiveFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder -} - -func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type sixFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder -} - -func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type sevenFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder -} - -func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type eightFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder - fieldHash8 int64 - fieldDecoder8 *structFieldDecoder -} - -func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - case decoder.fieldHash8: - decoder.fieldDecoder8.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type nineFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder - fieldHash8 int64 - fieldDecoder8 *structFieldDecoder - fieldHash9 int64 - fieldDecoder9 *structFieldDecoder -} - -func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - case decoder.fieldHash8: - decoder.fieldDecoder8.Decode(ptr, iter) - case decoder.fieldHash9: - decoder.fieldDecoder9.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type tenFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder - fieldHash8 int64 - fieldDecoder8 *structFieldDecoder - fieldHash9 int64 - fieldDecoder9 *structFieldDecoder - fieldHash10 int64 - fieldDecoder10 *structFieldDecoder -} - -func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - case decoder.fieldHash8: - decoder.fieldDecoder8.Decode(ptr, iter) - case decoder.fieldHash9: - decoder.fieldDecoder9.Decode(ptr, iter) - case decoder.fieldHash10: - decoder.fieldDecoder10.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type structFieldDecoder struct { - field reflect2.StructField - fieldDecoder ValDecoder -} - -func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - fieldPtr := decoder.field.UnsafeGet(ptr) - decoder.fieldDecoder.Decode(fieldPtr, iter) - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error()) - } -} - -type stringModeStringDecoder struct { - elemDecoder ValDecoder - cfg *frozenConfig -} - -func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.elemDecoder.Decode(ptr, iter) - str := *((*string)(ptr)) - tempIter := decoder.cfg.BorrowIterator([]byte(str)) - defer decoder.cfg.ReturnIterator(tempIter) - *((*string)(ptr)) = tempIter.ReadString() -} - -type stringModeNumberDecoder struct { - elemDecoder ValDecoder -} - -func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - if c != '"' { - iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) - return - } - decoder.elemDecoder.Decode(ptr, iter) - if iter.Error != nil { - return - } - c = iter.readByte() - if c != '"' { - iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) - return - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go deleted file mode 100644 index 152e3ef..0000000 --- a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go +++ /dev/null @@ -1,211 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "reflect" - "unsafe" -) - -func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { - type bindingTo struct { - binding *Binding - toName string - ignored bool - } - orderedBindings := []*bindingTo{} - structDescriptor := describeStruct(ctx, typ) - for _, binding := range structDescriptor.Fields { - for _, toName := range binding.ToNames { - new := &bindingTo{ - binding: binding, - toName: toName, - } - for _, old := range orderedBindings { - if old.toName != toName { - continue - } - old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding) - } - orderedBindings = append(orderedBindings, new) - } - } - if len(orderedBindings) == 0 { - return &emptyStructEncoder{} - } - finalOrderedFields := []structFieldTo{} - for _, bindingTo := range orderedBindings { - if !bindingTo.ignored { - finalOrderedFields = append(finalOrderedFields, structFieldTo{ - encoder: bindingTo.binding.Encoder.(*structFieldEncoder), - toName: bindingTo.toName, - }) - } - } - return &structEncoder{typ, finalOrderedFields} -} - -func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty { - encoder := createEncoderOfNative(ctx, typ) - if encoder != nil { - return encoder - } - kind := typ.Kind() - switch kind { - case reflect.Interface: - return &dynamicEncoder{typ} - case reflect.Struct: - return &structEncoder{typ: typ} - case reflect.Array: - return &arrayEncoder{} - case reflect.Slice: - return &sliceEncoder{} - case reflect.Map: - return encoderOfMap(ctx, typ) - case reflect.Ptr: - return &OptionalEncoder{} - default: - return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)} - } -} - -func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { - newTagged := new.Field.Tag().Get(cfg.getTagKey()) != "" - oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != "" - if newTagged { - if oldTagged { - if len(old.levels) > len(new.levels) { - return true, false - } else if len(new.levels) > len(old.levels) { - return false, true - } else { - return true, true - } - } else { - return true, false - } - } else { - if oldTagged { - return true, false - } - if len(old.levels) > len(new.levels) { - return true, false - } else if len(new.levels) > len(old.levels) { - return false, true - } else { - return true, true - } - } -} - -type structFieldEncoder struct { - field reflect2.StructField - fieldEncoder ValEncoder - omitempty bool -} - -func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - fieldPtr := encoder.field.UnsafeGet(ptr) - encoder.fieldEncoder.Encode(fieldPtr, stream) - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error()) - } -} - -func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { - fieldPtr := encoder.field.UnsafeGet(ptr) - return encoder.fieldEncoder.IsEmpty(fieldPtr) -} - -func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { - isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil) - if !converted { - return false - } - fieldPtr := encoder.field.UnsafeGet(ptr) - return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) -} - -type IsEmbeddedPtrNil interface { - IsEmbeddedPtrNil(ptr unsafe.Pointer) bool -} - -type structEncoder struct { - typ reflect2.Type - fields []structFieldTo -} - -type structFieldTo struct { - encoder *structFieldEncoder - toName string -} - -func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteObjectStart() - isNotFirst := false - for _, field := range encoder.fields { - if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { - continue - } - if field.encoder.IsEmbeddedPtrNil(ptr) { - continue - } - if isNotFirst { - stream.WriteMore() - } - stream.WriteObjectField(field.toName) - field.encoder.Encode(ptr, stream) - isNotFirst = true - } - stream.WriteObjectEnd() - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error()) - } -} - -func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type emptyStructEncoder struct { -} - -func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteEmptyObject() -} - -func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type stringModeNumberEncoder struct { - elemEncoder ValEncoder -} - -func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.writeByte('"') - encoder.elemEncoder.Encode(ptr, stream) - stream.writeByte('"') -} - -func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.elemEncoder.IsEmpty(ptr) -} - -type stringModeStringEncoder struct { - elemEncoder ValEncoder - cfg *frozenConfig -} - -func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - tempStream := encoder.cfg.BorrowStream(nil) - tempStream.Attachment = stream.Attachment - defer encoder.cfg.ReturnStream(tempStream) - encoder.elemEncoder.Encode(ptr, tempStream) - stream.WriteString(string(tempStream.Buffer())) -} - -func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.elemEncoder.IsEmpty(ptr) -} diff --git a/vendor/github.com/json-iterator/go/stream.go b/vendor/github.com/json-iterator/go/stream.go deleted file mode 100644 index 23d8a3a..0000000 --- a/vendor/github.com/json-iterator/go/stream.go +++ /dev/null @@ -1,210 +0,0 @@ -package jsoniter - -import ( - "io" -) - -// stream is a io.Writer like object, with JSON specific write functions. -// Error is not returned as return value, but stored as Error member on this stream instance. -type Stream struct { - cfg *frozenConfig - out io.Writer - buf []byte - Error error - indention int - Attachment interface{} // open for customized encoder -} - -// NewStream create new stream instance. -// cfg can be jsoniter.ConfigDefault. -// out can be nil if write to internal buffer. -// bufSize is the initial size for the internal buffer in bytes. -func NewStream(cfg API, out io.Writer, bufSize int) *Stream { - return &Stream{ - cfg: cfg.(*frozenConfig), - out: out, - buf: make([]byte, 0, bufSize), - Error: nil, - indention: 0, - } -} - -// Pool returns a pool can provide more stream with same configuration -func (stream *Stream) Pool() StreamPool { - return stream.cfg -} - -// Reset reuse this stream instance by assign a new writer -func (stream *Stream) Reset(out io.Writer) { - stream.out = out - stream.buf = stream.buf[:0] -} - -// Available returns how many bytes are unused in the buffer. -func (stream *Stream) Available() int { - return cap(stream.buf) - len(stream.buf) -} - -// Buffered returns the number of bytes that have been written into the current buffer. -func (stream *Stream) Buffered() int { - return len(stream.buf) -} - -// Buffer if writer is nil, use this method to take the result -func (stream *Stream) Buffer() []byte { - return stream.buf -} - -// SetBuffer allows to append to the internal buffer directly -func (stream *Stream) SetBuffer(buf []byte) { - stream.buf = buf -} - -// Write writes the contents of p into the buffer. -// It returns the number of bytes written. -// If nn < len(p), it also returns an error explaining -// why the write is short. -func (stream *Stream) Write(p []byte) (nn int, err error) { - stream.buf = append(stream.buf, p...) - if stream.out != nil { - nn, err = stream.out.Write(stream.buf) - stream.buf = stream.buf[nn:] - return - } - return len(p), nil -} - -// WriteByte writes a single byte. -func (stream *Stream) writeByte(c byte) { - stream.buf = append(stream.buf, c) -} - -func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { - stream.buf = append(stream.buf, c1, c2) -} - -func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { - stream.buf = append(stream.buf, c1, c2, c3) -} - -func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { - stream.buf = append(stream.buf, c1, c2, c3, c4) -} - -func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { - stream.buf = append(stream.buf, c1, c2, c3, c4, c5) -} - -// Flush writes any buffered data to the underlying io.Writer. -func (stream *Stream) Flush() error { - if stream.out == nil { - return nil - } - if stream.Error != nil { - return stream.Error - } - _, err := stream.out.Write(stream.buf) - if err != nil { - if stream.Error == nil { - stream.Error = err - } - return err - } - stream.buf = stream.buf[:0] - return nil -} - -// WriteRaw write string out without quotes, just like []byte -func (stream *Stream) WriteRaw(s string) { - stream.buf = append(stream.buf, s...) -} - -// WriteNil write null to stream -func (stream *Stream) WriteNil() { - stream.writeFourBytes('n', 'u', 'l', 'l') -} - -// WriteTrue write true to stream -func (stream *Stream) WriteTrue() { - stream.writeFourBytes('t', 'r', 'u', 'e') -} - -// WriteFalse write false to stream -func (stream *Stream) WriteFalse() { - stream.writeFiveBytes('f', 'a', 'l', 's', 'e') -} - -// WriteBool write true or false into stream -func (stream *Stream) WriteBool(val bool) { - if val { - stream.WriteTrue() - } else { - stream.WriteFalse() - } -} - -// WriteObjectStart write { with possible indention -func (stream *Stream) WriteObjectStart() { - stream.indention += stream.cfg.indentionStep - stream.writeByte('{') - stream.writeIndention(0) -} - -// WriteObjectField write "field": with possible indention -func (stream *Stream) WriteObjectField(field string) { - stream.WriteString(field) - if stream.indention > 0 { - stream.writeTwoBytes(':', ' ') - } else { - stream.writeByte(':') - } -} - -// WriteObjectEnd write } with possible indention -func (stream *Stream) WriteObjectEnd() { - stream.writeIndention(stream.cfg.indentionStep) - stream.indention -= stream.cfg.indentionStep - stream.writeByte('}') -} - -// WriteEmptyObject write {} -func (stream *Stream) WriteEmptyObject() { - stream.writeByte('{') - stream.writeByte('}') -} - -// WriteMore write , with possible indention -func (stream *Stream) WriteMore() { - stream.writeByte(',') - stream.writeIndention(0) -} - -// WriteArrayStart write [ with possible indention -func (stream *Stream) WriteArrayStart() { - stream.indention += stream.cfg.indentionStep - stream.writeByte('[') - stream.writeIndention(0) -} - -// WriteEmptyArray write [] -func (stream *Stream) WriteEmptyArray() { - stream.writeTwoBytes('[', ']') -} - -// WriteArrayEnd write ] with possible indention -func (stream *Stream) WriteArrayEnd() { - stream.writeIndention(stream.cfg.indentionStep) - stream.indention -= stream.cfg.indentionStep - stream.writeByte(']') -} - -func (stream *Stream) writeIndention(delta int) { - if stream.indention == 0 { - return - } - stream.writeByte('\n') - toWrite := stream.indention - delta - for i := 0; i < toWrite; i++ { - stream.buf = append(stream.buf, ' ') - } -} diff --git a/vendor/github.com/json-iterator/go/stream_float.go b/vendor/github.com/json-iterator/go/stream_float.go deleted file mode 100644 index 826aa59..0000000 --- a/vendor/github.com/json-iterator/go/stream_float.go +++ /dev/null @@ -1,111 +0,0 @@ -package jsoniter - -import ( - "fmt" - "math" - "strconv" -) - -var pow10 []uint64 - -func init() { - pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} -} - -// WriteFloat32 write float32 to stream -func (stream *Stream) WriteFloat32(val float32) { - if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - abs := math.Abs(float64(val)) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - if float32(abs) < 1e-6 || float32(abs) >= 1e21 { - fmt = 'e' - } - } - stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32) -} - -// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster -func (stream *Stream) WriteFloat32Lossy(val float32) { - if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - if val < 0 { - stream.writeByte('-') - val = -val - } - if val > 0x4ffffff { - stream.WriteFloat32(val) - return - } - precision := 6 - exp := uint64(1000000) // 6 - lval := uint64(float64(val)*float64(exp) + 0.5) - stream.WriteUint64(lval / exp) - fval := lval % exp - if fval == 0 { - return - } - stream.writeByte('.') - for p := precision - 1; p > 0 && fval < pow10[p]; p-- { - stream.writeByte('0') - } - stream.WriteUint64(fval) - for stream.buf[len(stream.buf)-1] == '0' { - stream.buf = stream.buf[:len(stream.buf)-1] - } -} - -// WriteFloat64 write float64 to stream -func (stream *Stream) WriteFloat64(val float64) { - if math.IsInf(val, 0) || math.IsNaN(val) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - abs := math.Abs(val) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - if abs < 1e-6 || abs >= 1e21 { - fmt = 'e' - } - } - stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64) -} - -// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster -func (stream *Stream) WriteFloat64Lossy(val float64) { - if math.IsInf(val, 0) || math.IsNaN(val) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - if val < 0 { - stream.writeByte('-') - val = -val - } - if val > 0x4ffffff { - stream.WriteFloat64(val) - return - } - precision := 6 - exp := uint64(1000000) // 6 - lval := uint64(val*float64(exp) + 0.5) - stream.WriteUint64(lval / exp) - fval := lval % exp - if fval == 0 { - return - } - stream.writeByte('.') - for p := precision - 1; p > 0 && fval < pow10[p]; p-- { - stream.writeByte('0') - } - stream.WriteUint64(fval) - for stream.buf[len(stream.buf)-1] == '0' { - stream.buf = stream.buf[:len(stream.buf)-1] - } -} diff --git a/vendor/github.com/json-iterator/go/stream_int.go b/vendor/github.com/json-iterator/go/stream_int.go deleted file mode 100644 index d1059ee..0000000 --- a/vendor/github.com/json-iterator/go/stream_int.go +++ /dev/null @@ -1,190 +0,0 @@ -package jsoniter - -var digits []uint32 - -func init() { - digits = make([]uint32, 1000) - for i := uint32(0); i < 1000; i++ { - digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' - if i < 10 { - digits[i] += 2 << 24 - } else if i < 100 { - digits[i] += 1 << 24 - } - } -} - -func writeFirstBuf(space []byte, v uint32) []byte { - start := v >> 24 - if start == 0 { - space = append(space, byte(v>>16), byte(v>>8)) - } else if start == 1 { - space = append(space, byte(v>>8)) - } - space = append(space, byte(v)) - return space -} - -func writeBuf(buf []byte, v uint32) []byte { - return append(buf, byte(v>>16), byte(v>>8), byte(v)) -} - -// WriteUint8 write uint8 to stream -func (stream *Stream) WriteUint8(val uint8) { - stream.buf = writeFirstBuf(stream.buf, digits[val]) -} - -// WriteInt8 write int8 to stream -func (stream *Stream) WriteInt8(nval int8) { - var val uint8 - if nval < 0 { - val = uint8(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint8(nval) - } - stream.buf = writeFirstBuf(stream.buf, digits[val]) -} - -// WriteUint16 write uint16 to stream -func (stream *Stream) WriteUint16(val uint16) { - q1 := val / 1000 - if q1 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[val]) - return - } - r1 := val - q1*1000 - stream.buf = writeFirstBuf(stream.buf, digits[q1]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return -} - -// WriteInt16 write int16 to stream -func (stream *Stream) WriteInt16(nval int16) { - var val uint16 - if nval < 0 { - val = uint16(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint16(nval) - } - stream.WriteUint16(val) -} - -// WriteUint32 write uint32 to stream -func (stream *Stream) WriteUint32(val uint32) { - q1 := val / 1000 - if q1 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[val]) - return - } - r1 := val - q1*1000 - q2 := q1 / 1000 - if q2 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q1]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r2 := q1 - q2*1000 - q3 := q2 / 1000 - if q3 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q2]) - } else { - r3 := q2 - q3*1000 - stream.buf = append(stream.buf, byte(q3+'0')) - stream.buf = writeBuf(stream.buf, digits[r3]) - } - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) -} - -// WriteInt32 write int32 to stream -func (stream *Stream) WriteInt32(nval int32) { - var val uint32 - if nval < 0 { - val = uint32(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint32(nval) - } - stream.WriteUint32(val) -} - -// WriteUint64 write uint64 to stream -func (stream *Stream) WriteUint64(val uint64) { - q1 := val / 1000 - if q1 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[val]) - return - } - r1 := val - q1*1000 - q2 := q1 / 1000 - if q2 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q1]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r2 := q1 - q2*1000 - q3 := q2 / 1000 - if q3 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q2]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r3 := q2 - q3*1000 - q4 := q3 / 1000 - if q4 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q3]) - stream.buf = writeBuf(stream.buf, digits[r3]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r4 := q3 - q4*1000 - q5 := q4 / 1000 - if q5 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q4]) - stream.buf = writeBuf(stream.buf, digits[r4]) - stream.buf = writeBuf(stream.buf, digits[r3]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r5 := q4 - q5*1000 - q6 := q5 / 1000 - if q6 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q5]) - } else { - stream.buf = writeFirstBuf(stream.buf, digits[q6]) - r6 := q5 - q6*1000 - stream.buf = writeBuf(stream.buf, digits[r6]) - } - stream.buf = writeBuf(stream.buf, digits[r5]) - stream.buf = writeBuf(stream.buf, digits[r4]) - stream.buf = writeBuf(stream.buf, digits[r3]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) -} - -// WriteInt64 write int64 to stream -func (stream *Stream) WriteInt64(nval int64) { - var val uint64 - if nval < 0 { - val = uint64(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint64(nval) - } - stream.WriteUint64(val) -} - -// WriteInt write int to stream -func (stream *Stream) WriteInt(val int) { - stream.WriteInt64(int64(val)) -} - -// WriteUint write uint to stream -func (stream *Stream) WriteUint(val uint) { - stream.WriteUint64(uint64(val)) -} diff --git a/vendor/github.com/json-iterator/go/stream_str.go b/vendor/github.com/json-iterator/go/stream_str.go deleted file mode 100644 index 54c2ba0..0000000 --- a/vendor/github.com/json-iterator/go/stream_str.go +++ /dev/null @@ -1,372 +0,0 @@ -package jsoniter - -import ( - "unicode/utf8" -) - -// htmlSafeSet holds the value true if the ASCII character with the given -// array position can be safely represented inside a JSON string, embedded -// inside of HTML