feat: repo health check (#16) #17
|  | @ -1,75 +1,90 @@ | ||||||
| package healthcheck | package healthcheck | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"crypto/sha256" | ||||||
|  | 	"encoding/hex" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | 	"strings" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // fileExists checks if a file exists at the specified path.
 | // getChecksum calculates the SHA-256 checksum of a file
 | ||||||
| func fileExists(filePath string) bool { | func getChecksum(filePath string) (string, error) { | ||||||
| 	_, err := os.Stat(filePath) | 	// Open the file
 | ||||||
| 	return !os.IsNotExist(err) | 	file, err := os.Open(filePath) | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // filesMatch checks if two files are identical.
 |  | ||||||
| func filesMatch(file1, file2 string) (bool, error) { |  | ||||||
| 	f1, err := os.Open(file1) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 	defer f1.Close() | 	defer file.Close() | ||||||
| 
 | 
 | ||||||
| 	f2, err := os.Open(file2) | 	// Calculate SHA-256
 | ||||||
|  | 	hash := sha256.New() | ||||||
|  | 	if _, err := io.Copy(hash, file); err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return hex.EncodeToString(hash.Sum(nil)), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // checkFileChecksum checks if a single file's checksum matches the expected value
 | ||||||
|  | func checkFileChecksum(rootDir, fileName, expectedChecksum string) (bool, string) { | ||||||
|  | 	filePath := filepath.Join(rootDir, strings.TrimSpace(fileName)) | ||||||
|  | 	actualChecksum, err := getChecksum(filePath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, err | 		return false, fmt.Sprintf("Error reading file %s: %v", filePath, err) | ||||||
| 	} |  | ||||||
| 	defer f2.Close() |  | ||||||
| 
 |  | ||||||
| 	scanner1 := bufio.NewScanner(f1) |  | ||||||
| 	scanner2 := bufio.NewScanner(f2) |  | ||||||
| 
 |  | ||||||
| 	for scanner1.Scan() && scanner2.Scan() { |  | ||||||
| 		line1 := scanner1.Text() |  | ||||||
| 		line2 := scanner2.Text() |  | ||||||
| 
 |  | ||||||
| 		if line1 != line2 { |  | ||||||
| 			return false, nil |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if scanner1.Scan() || scanner2.Scan() { | 	if actualChecksum == expectedChecksum { | ||||||
| 		// One file has more lines than the other
 | 		return true, fmt.Sprintf("Checksum for %s passed!", filePath) | ||||||
| 		return false, nil | 	} else { | ||||||
|  | 		return false, fmt.Sprintf("Checksum for %s failed. Expected %s, but got %s. Please revert the changes!", filePath, expectedChecksum, actualChecksum) | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return true, nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // VerifyDirectory checks if the contents of two directories are identical.
 | func VerifyFiles(rootDir string,checkFileNameList string, checkFileSumList string ) error { | ||||||
| func VerifyDirectory(rootDir, compareDir string) error { | 	// Parse command-line arguments
 | ||||||
| 	err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { | 	// checkFileNameList := flag.String("checkFileNameList", "", "Comma-separated list of files to check.")
 | ||||||
| 		if err != nil { | 	// checkFileSumList := flag.String("checkFileSumList", "", "Comma-separated list of expected checksums.")
 | ||||||
| 			return fmt.Errorf("error walking directory: %w", err) | 	// rootDir := flag.String("rootDir", ".", "Root directory containing the files.")
 | ||||||
|  | 	// flag.Parse()
 | ||||||
|  | 
 | ||||||
|  | 	// Process input file names and checksums
 | ||||||
|  | 	fileNames := strings.Split(checkFileNameList, ",") | ||||||
|  | 	checkSums := strings.Split(checkFileSumList, ",") | ||||||
|  | 
 | ||||||
|  | 	// Check if the number of files matches the number of checksums
 | ||||||
|  | 	if len(fileNames) == 0 { | ||||||
|  | 		return fmt.Errorf("No checksum happened") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(fileNames) != len(checkSums) { | ||||||
|  | 		return fmt.Errorf("Error: The number of files and checksums do not match.") | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	allPassed := true | ||||||
|  | 	var errorMessages []string | ||||||
|  | 
 | ||||||
|  | 	// Check each file's checksum
 | ||||||
|  | 	for i, fileName := range fileNames { | ||||||
|  | 		expectedChecksum := strings.TrimSpace(checkSums[i]) | ||||||
|  | 		passed, message := checkFileChecksum(rootDir, fileName, expectedChecksum) | ||||||
|  | 		return fmt.Errorf(message) | ||||||
|  | 		if !passed { | ||||||
|  | 			allPassed = false | ||||||
|  | 			errorMessages = append(errorMessages, message) | ||||||
| 		} | 		} | ||||||
| 		if !info.IsDir() { | 	} | ||||||
| 			relPath, _ := filepath.Rel(rootDir, path) | 
 | ||||||
| 			file2 := filepath.Join(compareDir, relPath) | 	if allPassed { | ||||||
| 			if !fileExists(file2) { | 		return fmt.Errorf("Congratulations! All checksums passed!") | ||||||
| 				return fmt.Errorf("File %s is missing. Please immediately revert your changes!\n", | 	} else { | ||||||
| 					filepath.Join(rootDir, relPath)) | 		return fmt.Errorf("Some checksums failed. Please review the errors below:") | ||||||
| 			} | 		for _, msg := range errorMessages { | ||||||
| 			match, err := filesMatch(path, file2) | 			return fmt.Errorf(msg) | ||||||
| 			if err != nil { |  | ||||||
| 				return fmt.Errorf("error matching files: %w", err) |  | ||||||
| 			} |  | ||||||
| 			if !match { |  | ||||||
| 				return fmt.Errorf("File %s is altered. Please revert your changes or contact the teaching team if you have a valid reason for adjusting them.\n", |  | ||||||
| 					filepath.Join(rootDir, relPath)) |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		return nil | 	} | ||||||
| 	}) | 	return nil | ||||||
| 	return err |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user