<commit_before>//
//  PurchaseDownloadObserver.swift
//  mas-cli
//
//  Created by <NAME> on 21/08/2015.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

let csi = "\u{001B}["

@objc class PurchaseDownloadObserver: NSObject, CKDownloadQueueObserver {
    let purchase: SSPurchase
    var completionHandler: (() -> ())?
    var errorHandler: ((MASError) -> ())?
    
    init(purchase: SSPurchase) {
        self.purchase = purchase
    }
    
    func downloadQueue(queue: CKDownloadQueue, statusChangedForDownload download: SSDownload!) {
        if download.metadata.itemIdentifier != purchase.itemIdentifier {
            return
        }
        let status = download.status
        if status.failed || status.cancelled {
            queue.removeDownloadWithItemIdentifier(download.metadata.itemIdentifier)
        }
        else {
            progress(status.progressState)
        }
    }
    
    func downloadQueue(queue: CKDownloadQueue, changedWithAddition download: SSDownload!) {
        clearLine()
        print("==> Downloading " + download.metadata.title)
    }
    
    func downloadQueue(queue: CKDownloadQueue, changedWithRemoval download: SSDownload!) {
        clearLine()
        let status = download.status
        if status.failed {
            print("==> Download Failed")
            errorHandler?(MASError(code: .DownloadFailed, sourceError: status.error))
        }
        else if status.cancelled {
            print("==> Download Cancelled")
            errorHandler?(MASError(code: .Cancelled))
        }
        else {
            print("==> Installed " + download.metadata.title)
            completionHandler?()
        }
    }
}

struct ProgressState {
    let percentComplete: Float
    let phase: String
    
    var percentage: String {
        return String(format: "%.1f%%", arguments: [floor(percentComplete * 100)])
    }
}

func progress(state: ProgressState) {
    // Don't display the progress bar if we're not on a terminal
    if isatty(fileno(stdout)) == 0 {
        return
    }
    
    let barLength = 60
    
    let completeLength = Int(state.percentComplete * Float(barLength))
    var bar = ""
    for i in 0..<barLength {
        if i < completeLength {
            bar += "#"
        }
        else {
            bar += "-"
        }
    }
    clearLine()
    print("\(bar) \(state.percentage) \(state.phase)", terminator: "")
    fflush(stdout)
}

func clearLine() {
    print("\(csi)2K\(csi)0G")
}

extension SSDownloadStatus {
    var progressState: ProgressState {
        let phase = activePhase?.phaseDescription ?? "Waiting"
        return ProgressState(percentComplete: percentComplete, phase: phase)
    }
}

extension SSDownloadPhase {
    var phaseDescription: String {
        switch phaseType {
        case 0:
            return "Downloading"
        case 1:
            return "Installing"
        default:
            return "Waiting"
        }
    }
}<commit_msg>Ensure we only display terminal codes in a tty<commit_after>//
//  PurchaseDownloadObserver.swift
//  mas-cli
//
//  Created by <NAME> on 21/08/2015.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

let csi = "\u{001B}["

@objc class PurchaseDownloadObserver: NSObject, CKDownloadQueueObserver {
    let purchase: SSPurchase
    var completionHandler: (() -> ())?
    var errorHandler: ((MASError) -> ())?
    
    init(purchase: SSPurchase) {
        self.purchase = purchase
    }
    
    func downloadQueue(queue: CKDownloadQueue, statusChangedForDownload download: SSDownload!) {
        if download.metadata.itemIdentifier != purchase.itemIdentifier {
            return
        }
        let status = download.status
        if status.failed || status.cancelled {
            queue.removeDownloadWithItemIdentifier(download.metadata.itemIdentifier)
        }
        else {
            progress(status.progressState)
        }
    }
    
    func downloadQueue(queue: CKDownloadQueue, changedWithAddition download: SSDownload!) {
        clearLine()
        print("==> Downloading " + download.metadata.title)
    }
    
    func downloadQueue(queue: CKDownloadQueue, changedWithRemoval download: SSDownload!) {
        clearLine()
        let status = download.status
        if status.failed {
            print("==> Download Failed")
            errorHandler?(MASError(code: .DownloadFailed, sourceError: status.error))
        }
        else if status.cancelled {
            print("==> Download Cancelled")
            errorHandler?(MASError(code: .Cancelled))
        }
        else {
            print("==> Installed " + download.metadata.title)
            completionHandler?()
        }
    }
}

struct ProgressState {
    let percentComplete: Float
    let phase: String
    
    var percentage: String {
        return String(format: "%.1f%%", arguments: [floor(percentComplete * 100)])
    }
}

func progress(state: ProgressState) {
    // Don't display the progress bar if we're not on a terminal
    if isatty(fileno(stdout)) == 0 {
        return
    }
    
    let barLength = 60
    
    let completeLength = Int(state.percentComplete * Float(barLength))
    var bar = ""
    for i in 0..<barLength {
        if i < completeLength {
            bar += "#"
        }
        else {
            bar += "-"
        }
    }
    clearLine()
    print("\(bar) \(state.percentage) \(state.phase)", terminator: "")
    fflush(stdout)
}

func clearLine() {
    guard isatty(fileno(stdout)) != 0 else {
        return
    }
    print("\(csi)2K\(csi)0G")
}

extension SSDownloadStatus {
    var progressState: ProgressState {
        let phase = activePhase?.phaseDescription ?? "Waiting"
        return ProgressState(percentComplete: percentComplete, phase: phase)
    }
}

extension SSDownloadPhase {
    var phaseDescription: String {
        switch phaseType {
        case 0:
            return "Downloading"
        case 1:
            return "Installing"
        default:
            return "Waiting"
        }
    }
}
{'fraction_non_alphanumeric': 0.11083291604072776, 'fraction_numerical': 0.009180437322650642, 'mean_word_length': 2.1957333333333335, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 60, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7651912', 'n_tokens_mistral': 1754, 'n_tokens_neox': 1674, 'n_words': 395}