You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// CLIArgs represents the parsed command line arguments for the enhanced CLI interface
@@ -73,29 +74,58 @@ func NewCLIArgs() *CLIArgs {
73
74
// ValidateURL validates that the provided URL is valid and accessible
74
75
funcValidateURL(rawURLstring) error {
75
76
ifrawURL=="" {
76
-
returnfmt.Errorf("URL cannot be empty")
77
+
returnfmt.Errorf("Error: No URL provided\n\nA download URL is required to proceed.\n\nUsage:\n dr <URL>\n dr --url <URL>\n\nExamples:\n dr https://example.com/file.zip\n dr ftp://files.example.com/data.tar.gz")
78
+
}
79
+
80
+
// Trim whitespace that might cause parsing issues
81
+
rawURL=strings.TrimSpace(rawURL)
82
+
ifrawURL=="" {
83
+
returnfmt.Errorf("Error: Empty URL provided\n\nPlease provide a valid URL.\n\nExamples:\n dr https://example.com/file.zip\n dr ftp://files.example.com/data.tar.gz")
77
84
}
78
85
79
86
parsedURL, err:=url.ParseRequestURI(rawURL)
80
87
iferr!=nil {
81
-
returnfmt.Errorf("invalid URL format: %v\n\nPlease provide a complete URL including protocol.\n\nExamples:\n https://example.com/file.zip\n ftp://files.example.com/data.tar.gz", err)
88
+
// Provide more specific error messages based on common mistakes
89
+
if!strings.Contains(rawURL, "://") {
90
+
returnfmt.Errorf("Error: Invalid URL format - missing protocol\n\nURL: %s\n\nThe URL must include a protocol (http://, https://, or ftp://).\n\nDid you mean:\n https://%s\n http://%s", rawURL, rawURL, rawURL)
91
+
}
92
+
returnfmt.Errorf("Error: Invalid URL format\n\nURL: %s\nReason: %v\n\nPlease provide a complete URL including protocol.\n\nExamples:\n https://example.com/file.zip\n ftp://files.example.com/data.tar.gz", rawURL, err)
returnfmt.Errorf("URL must include a hostname\n\nExample: https://example.com/file.zip")
112
+
returnfmt.Errorf("Error: Invalid URL - missing hostname\n\nURL: %s\n\nThe URL must include a hostname after the protocol.\n\nExample: https://example.com/file.zip", rawURL)
returnfmt.Errorf("Error: Invalid hostname format\n\nURL: %s\n\nHostname cannot start or end with a dot.\n\nExample: https://example.com/file.zip", rawURL)
93
123
}
94
124
95
125
returnnil
96
126
}
97
127
98
-
// ValidatePath validates that the provided path is validand writable
128
+
// ValidatePath validates that the provided path is valid, writable, and has sufficient disk space
99
129
funcValidatePath(pathstring) error {
100
130
ifpath=="" {
101
131
returnnil// Empty path is valid (will use current directory)
returnfmt.Errorf("parent directory '%s' does not exist", parentDir)
153
+
ifos.IsNotExist(parentErr) {
154
+
returnfmt.Errorf("Error: Parent directory does not exist\n\nPath: %s\nParent directory: %s\n\nPlease create the directory first or choose an existing location.", path, parentDir)
returnfmt.Errorf("parent path '%s' is not a directory", parentDir)
159
+
returnfmt.Errorf("Error: Parent path is not a directory\n\nPath: %s\nParent path: %s\n\nThe parent path must be a directory, not a file.", path, parentDir)
122
160
}
123
-
// Check write permission on parent directory
124
-
returncheckWritePermission(parentDir)
161
+
// Check write permission and disk space on parent directory
returnfmt.Errorf("Error: Cannot access path\n\nPath: %s\nReason: %v\n\nPlease check that the path exists and you have permission to access it.", path, err)
127
168
}
128
169
129
-
// If path exists and is a directory, check write permission
170
+
// If path exists and is a directory, check write permission and disk space
130
171
ifinfo.IsDir() {
131
-
returncheckWritePermission(absPath)
172
+
iferr:=checkWritePermission(absPath); err!=nil {
173
+
returnerr
174
+
}
175
+
returncheckDiskSpace(absPath)
132
176
}
133
177
134
-
// If path exists and is a file, check write permission on parent directory
178
+
// If path exists and is a file, check write permission and disk space on parent directory
returnfmt.Errorf("directory '%s' is not writable: %v", dir, err)
192
+
ifos.IsPermission(err) {
193
+
returnfmt.Errorf("Error: Permission denied\n\nDirectory: %s\n\nYou don't have write permission to this directory.\n\nSolutions:\n - Choose a different directory (e.g., your home directory)\n - Run with appropriate permissions\n - Check directory ownership and permissions", dir)
194
+
}
195
+
returnfmt.Errorf("Error: Cannot write to directory\n\nDirectory: %s\nReason: %v\n\nPlease ensure the directory is writable.", dir, err)
// checkDiskSpace checks if there's sufficient disk space available
203
+
funccheckDiskSpace(dirstring) error {
204
+
// Get disk usage information
205
+
varstat syscall.Statfs_t
206
+
err:=syscall.Statfs(dir, &stat)
207
+
iferr!=nil {
208
+
// If we can't get disk space info, just warn but don't fail
209
+
// This might happen on some filesystems or in containers
210
+
returnnil
211
+
}
212
+
213
+
// Calculate available space in bytes
214
+
availableBytes:=stat.Bavail*uint64(stat.Bsize)
215
+
216
+
// Require at least 100MB of free space as a safety margin
217
+
constminRequiredBytes=100*1024*1024// 100MB
218
+
219
+
ifavailableBytes<minRequiredBytes {
220
+
returnfmt.Errorf("Error: Insufficient disk space\n\nDirectory: %s\nAvailable space: %s\nMinimum required: %s\n\nPlease free up disk space or choose a different location.",
221
+
dir,
222
+
formatBytes(availableBytes),
223
+
formatBytes(minRequiredBytes))
224
+
}
225
+
226
+
// Warn if less than 1GB available
227
+
constwarnThresholdBytes=1024*1024*1024// 1GB
228
+
ifavailableBytes<warnThresholdBytes {
229
+
fmt.Fprintf(os.Stderr, "Warning: Low disk space\n\nDirectory: %s\nAvailable space: %s\n\nConsider freeing up space before downloading large files.\n\n",
230
+
dir, formatBytes(availableBytes))
231
+
}
232
+
233
+
returnnil
234
+
}
235
+
236
+
// formatBytes formats byte count as human-readable string
returnnil// No validation needed when segments are disabled
156
254
}
157
255
158
256
ifsegments<1 {
159
-
returnfmt.Errorf("segment countmust be at least 1, got %d\n\nSuggestion: Use --segments 4 for optimal performance", segments)
257
+
returnfmt.Errorf("Error: Invalid segment count\n\nValue: %d\n\nSegment count must be at least 1.\n\nRecommended values:\n --segments 4 (default, good for most files)\n --segments 8 (for large files or fast connections)\n --segments 1 (single-threaded download)", segments)
160
258
}
161
259
162
260
ifsegments>32 {
163
-
returnfmt.Errorf("segment count too high: %d\n\nUsing too many segments may hurt performance.\nSuggestion: Use --segments 8 or fewer", segments)
261
+
returnfmt.Errorf("Error: Too many segments\n\nValue: %d\nMaximum: 32\n\nUsing too many segments can hurt performance and may be blocked by servers.\n\nRecommended values:\n --segments 4 (default)\n --segments 8 (for large files)\n --segments 16 (maximum for most use cases)", segments)
164
262
}
165
263
166
264
ifsegmentSize<0 {
167
-
returnfmt.Errorf("segment sizecannot be negative: %d", segmentSize)
265
+
returnfmt.Errorf("Error: Invalid segment size\n\nValue: %d bytes\n\nSegment size cannot be negative.\n\nValid options:\n --segment-size 0 (auto-calculate based on file size)\n --segment-size 1048576 (1MB segments)\n --segment-size 10485760 (10MB segments)", segmentSize)
fmt.Fprintf(os.Stderr, "Warning: Very large segment size\n\nValue: %s\n\nLarge segments may reduce the benefits of parallel downloading.\nConsider using smaller segments (1-10MB) for better performance.\n\n", formatBytes(uint64(segmentSize)))
fmt.Fprintf(os.Stderr, "Warning: Large estimated download size\n\nSegments: %d\nSegment size: %s\nEstimated total: %s\n\nThis configuration may not be suitable for smaller files.\nConsider using --segment-size 0 for automatic sizing.\n\n",
0 commit comments