diff --git a/README.md b/README.md index e5edf0a..2a0998f 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Run `mint help` to see usage instructions. - **which**: Print the path to an installed package executable. - **uninstall**: Uninstalls a package by name. - **bootstrap**: Installs all the packages in your [Mintfile](#mintfile), by default, without linking them globally +- **outdated**: List all in your [Mintfile](#mintfile), by default, installed and linked packages that are outdated. **Package reference** diff --git a/Sources/MintCLI/Commands/OutdatedCommand.swift b/Sources/MintCLI/Commands/OutdatedCommand.swift new file mode 100644 index 0000000..1fddb4d --- /dev/null +++ b/Sources/MintCLI/Commands/OutdatedCommand.swift @@ -0,0 +1,19 @@ + +import Foundation +import MintKit +import PathKit +import SwiftCLI + +class OutdatedCommand: MintfileCommand { + + init(mint: Mint) { + super.init(mint: mint, + name: "outdated", + description: "List all the currently installed and linked packages that are outdated.") + } + + override func execute() throws { + try super.execute() + try mint.outdated() + } +} diff --git a/Sources/MintCLI/MintCLI.swift b/Sources/MintCLI/MintCLI.swift index a163c0e..2b06150 100644 --- a/Sources/MintCLI/MintCLI.swift +++ b/Sources/MintCLI/MintCLI.swift @@ -32,6 +32,7 @@ public class MintCLI { ListCommand(mint: mint), BootstrapCommand(mint: mint), WhichCommand(mint: mint), + OutdatedCommand(mint: mint), ]) } diff --git a/Sources/MintKit/Mint.swift b/Sources/MintKit/Mint.swift index 4a7ee55..1ce9c13 100644 --- a/Sources/MintKit/Mint.swift +++ b/Sources/MintKit/Mint.swift @@ -497,6 +497,46 @@ public class Mint { } } + public func outdated() throws { + + let mintFile = try Mintfile(path: mintFilePath) + + guard !mintFile.packages.isEmpty else { + standardOut <<< "🌱 Mintfile is empty" + return + } + + let packageCount = "\(mintFile.packages.count) \(mintFile.packages.count == 1 ? "package" : "packages")" + + if verbose { + output("Found \(packageCount) in \(mintFilePath.string)") + } + + var hasUpdates = false + for package in mintFile.packages { + + let tagOutput = try Task.capture(bash: "git ls-remote --tags --refs \(package.gitPath)") + let versions = tagOutput.stdout + .split(separator: "\n") + .map { String($0.split(separator: "\t").last!.split(separator: "/").last!) } + .compactMap { Version($0) } + .sorted() + + if let latestVersion = versions.last, + let packageVersion = Version(package.version) { + + if packageVersion < latestVersion { + hasUpdates = true + output("\(package.name) is outdated: \(packageVersion.description) -> \(latestVersion.description)".yellow) + } + } + } + + if !hasUpdates { + output("\(packageCount) up to date".green) + } + } + public func uninstall(name: String) throws { // find packages