Skip to content

Commit

Permalink
fix: Include Software Index source URLs in GitHub issues (#397)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbmorley authored Sep 26, 2024
1 parent 974ee1d commit dbdb062
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 109 deletions.
8 changes: 4 additions & 4 deletions OpoLua.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
D82639362783CAE500AB4086 /* TimerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82639352783CAE500AB4086 /* TimerRequest.swift */; };
D82A37B827A9B43F00D8F5F4 /* DirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82A37B727A9B43F00D8F5F4 /* DirectoryMonitor.swift */; };
D82D2FCC27AB4FBC001A4283 /* RecursiveDirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82D2FCB27AB4FBC001A4283 /* RecursiveDirectoryMonitor.swift */; };
D82D2FCE27AC3E62001A4283 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82D2FCD27AC3E62001A4283 /* Error.swift */; };
D82D76082C9142740040265E /* src in Resources */ = {isa = PBXBuildFile; fileRef = D82D76072C9142740040265E /* src */; };
D84ADB162771D937001ABFB4 /* Device.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84ADB152771D937001ABFB4 /* Device.swift */; };
D84ADB182771DAB9001ABFB4 /* NSNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84ADB172771DAB9001ABFB4 /* NSNotification.swift */; };
Expand Down Expand Up @@ -92,6 +91,7 @@
D8CCACAE27B2FE3D008C8122 /* NSLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CCACAD27B2FE3D008C8122 /* NSLock.swift */; };
D8CCACB027B2FE59008C8122 /* NSRecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CCACAF27B2FE59008C8122 /* NSRecursiveLock.swift */; };
D8D184F527BACAB5004DDFFD /* SoundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D184F427BACAB5004DDFFD /* SoundViewController.swift */; };
D8D22C1F2CA4E6B1003E2D5E /* Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D22C1E2CA4E6AF003E2D5E /* Metadata.swift */; };
D8D44C49279A0B87007340B5 /* TaskManagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D44C48279A0B87007340B5 /* TaskManagerViewController.swift */; };
D8D50117275928CF008C1BC9 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D50116275928CF008C1BC9 /* Scheduler.swift */; };
D8D6701527A72B2100D12E96 /* DestinationPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D6701427A72B2100D12E96 /* DestinationPickerViewController.swift */; };
Expand Down Expand Up @@ -163,7 +163,6 @@
D82639352783CAE500AB4086 /* TimerRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerRequest.swift; sourceTree = "<group>"; };
D82A37B727A9B43F00D8F5F4 /* DirectoryMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryMonitor.swift; sourceTree = "<group>"; };
D82D2FCB27AB4FBC001A4283 /* RecursiveDirectoryMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecursiveDirectoryMonitor.swift; sourceTree = "<group>"; };
D82D2FCD27AC3E62001A4283 /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
D82D76072C9142740040265E /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; path = src; sourceTree = "<group>"; };
D84ADB152771D937001ABFB4 /* Device.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Device.swift; sourceTree = "<group>"; };
D84ADB172771DAB9001ABFB4 /* NSNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNotification.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -221,6 +220,7 @@
D8CCACAD27B2FE3D008C8122 /* NSLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLock.swift; sourceTree = "<group>"; };
D8CCACAF27B2FE59008C8122 /* NSRecursiveLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRecursiveLock.swift; sourceTree = "<group>"; };
D8D184F427BACAB5004DDFFD /* SoundViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundViewController.swift; sourceTree = "<group>"; };
D8D22C1E2CA4E6AF003E2D5E /* Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Metadata.swift; sourceTree = "<group>"; };
D8D44C48279A0B87007340B5 /* TaskManagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskManagerViewController.swift; sourceTree = "<group>"; };
D8D50116275928CF008C1BC9 /* Scheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scheduler.swift; sourceTree = "<group>"; };
D8D6701427A72B2100D12E96 /* DestinationPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationPickerViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -309,6 +309,7 @@
D884A3D6277914CF008954A0 /* Installer.swift */,
D86724F12771672A009C7246 /* InterpreterThread.swift */,
D8FE6D902C92251B0058CE2E /* Legal.swift */,
D8D22C1E2CA4E6AF003E2D5E /* Metadata.swift */,
D884A3D02778E2CB008954A0 /* ObjectFileSystem.swift */,
D8C3BD662774BF1F003B1AD0 /* OpoLuaError.swift */,
D86724EF27715B88009C7246 /* Program.swift */,
Expand Down Expand Up @@ -370,7 +371,6 @@
D889134E274C181F00794D55 /* CGPoint.swift */,
D87A62732752A67500075CB8 /* CGSize.swift */,
D8EB6FF9275995DB00FC139F /* Dictionary.swift */,
D82D2FCD27AC3E62001A4283 /* Error.swift */,
D89A60792756A2CC00C9757F /* FileManager.swift */,
D80925602772939A00121E12 /* Graphics+CoreGraphics.swift */,
D8CCACAD27B2FE3D008C8122 /* NSLock.swift */,
Expand Down Expand Up @@ -629,7 +629,6 @@
D889134A274BF3B000794D55 /* TranslucentNavigationController.swift in Sources */,
DB9533FE27AC06A1001CF58D /* FlagSet.swift in Sources */,
D89A607E2756A98200C9757F /* ViewController.swift in Sources */,
D82D2FCE27AC3E62001A4283 /* Error.swift in Sources */,
D88A472227B82C720094A438 /* ApplicationIdentifier.swift in Sources */,
D8C43DF527C3EFEF00944A11 /* RootViewController.swift in Sources */,
D8F5CADB279D07A700A2DC3F /* ResourceViewController.swift in Sources */,
Expand Down Expand Up @@ -686,6 +685,7 @@
D8FE6D912C92251B0058CE2E /* Legal.swift in Sources */,
D80925612772939A00121E12 /* Graphics+CoreGraphics.swift in Sources */,
D84ADB182771DAB9001ABFB4 /* NSNotification.swift in Sources */,
D8D22C1F2CA4E6B1003E2D5E /* Metadata.swift in Sources */,
D88A472427B83D6E0094A438 /* FileMetadataCache.swift in Sources */,
D8891342274BF21900794D55 /* ChoiceViewController.swift in Sources */,
D8647C702793540500DCC261 /* TaskManager.swift in Sources */,
Expand Down
5 changes: 3 additions & 2 deletions OpoLua/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
rootViewController.showSettings()
}

func install(url: URL, preferredDestinationUrl: URL? = nil) {
func install(url: URL, preferredDestinationUrl: URL? = nil, sourceUrl: URL? = nil) {
let installerViewController = InstallerViewController(settings: settings,
url: url,
preferredDestinationUrl: preferredDestinationUrl)
preferredDestinationUrl: preferredDestinationUrl,
sourceUrl: sourceUrl)
installerViewController.installerDelegate = self
rootViewController.present(installerViewController, animated: true)
}
Expand Down
48 changes: 0 additions & 48 deletions OpoLua/Extensions/Error.swift

This file was deleted.

23 changes: 1 addition & 22 deletions OpoLua/Extensions/FileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,28 +194,7 @@ extension FileManager {
}

func isSystem(at url: URL) throws -> Bool {
guard url.lastPathComponent.hasSuffix(".system") else {
return false
}

let contents = try contentsOfDirectory(atPath: url.path).map { url.appendingPathComponent($0) }
let drives: Set<String> = ["c", "m"]

// Ensure there only folders named for valid drive letters present.
// N.B. This implementation is intetnionally strict. We can relax it as and when we find we need to.
for url in contents {
let name = url.lastPathComponent
if name.starts(with: ".") {
// Ignore hidden files.
continue
}
guard url.isDirectory,
drives.contains(name.lowercased())
else {
return false
}
}
return true
return url.lastPathComponent.hasSuffix(".system")
}

func detectSystemFileSystem(for url: URL) throws -> FileSystem? {
Expand Down
44 changes: 43 additions & 1 deletion OpoLua/Extensions/URL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,28 @@ import UIKit

extension URL {

static func gitHubIssue(title: String, description: String, labels: [String]) -> URL? {
private static func description(details: String, title: String, sourceUrl: URL?) -> String {
return """
## Description
_Please provide details of the program you were running, and what you were doing when you encountered the error._
## Metadata
| Key | Value |
| --- | --- |
| **Title** | \(title) |
| **Source URL** | \(sourceUrl?.absoluteString ?? "*unknown*") |
## Details
```
\(details)
```
"""
}

private static func gitHubIssueURL(title: String, description: String, labels: [String]) -> URL? {
var components = URLComponents()
components.scheme = "https"
components.host = "github.com"
Expand All @@ -36,6 +57,27 @@ extension URL {
return components.url
}

static func gitHubIssueURL(for error: Error, title: String, sourceUrl: URL?) -> URL? {
if let _ = error as? OpoInterpreter.BinaryDatabaseError {
return nil
} else if let _ = error as? OpoInterpreter.LeaveError {
return nil
} else if let _ = error as? OpoInterpreter.NativeBinaryError {
return nil
} else if let unimplementedOperation = error as? OpoInterpreter.UnimplementedOperationError {
let description = description(details: unimplementedOperation.detail, title: title, sourceUrl: sourceUrl)
return URL.gitHubIssueURL(title: "[\(title)] Unimplemented Operation: \(unimplementedOperation.operation)",
description: description,
labels: ["facerake", "bug"])
} else if let interpreterError = error as? OpoInterpreter.InterpreterError {
let description = description(details: interpreterError.detail, title: title, sourceUrl: sourceUrl)
return URL.gitHubIssueURL(title: "[\(title)] Internal Error: \(interpreterError.message)",
description: description,
labels: ["internal-error", "bug"])
}
return nil
}

var localizedName: String {
if self == FileManager.default.documentsUrl {
return UIDevice.current.localizedDocumentsName
Expand Down
7 changes: 5 additions & 2 deletions OpoLua/Model/Installer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,24 @@ class Installer {

let url: URL
let destinationUrl: URL
let fileSystem: FileSystem
let sourceUrl: URL?
let fileSystem: SystemFileSystem
let psilua = PsiLuaEnv()

weak var delegate: InstallerDelegate?

init(url: URL, destinationUrl: URL) {
init(url: URL, destinationUrl: URL, sourceUrl: URL?) {
self.url = url
self.destinationUrl = destinationUrl
self.sourceUrl = sourceUrl
self.fileSystem = SystemFileSystem(rootUrl: destinationUrl)
}

func run() {
DispatchQueue.global().async {
do {
try self.fileSystem.prepare()
self.fileSystem.metadata = Metadata(sourceUrl: self.sourceUrl)
try self.psilua.installSisFile(path: self.url.path, handler: self)
let item: Directory.Item?
if let systemType = try Directory.Item.system(url: self.destinationUrl, env: self.psilua) {
Expand Down
44 changes: 44 additions & 0 deletions OpoLua/Model/Metadata.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2021-2024 Jason Morley, Tom Sutcliffe
//
// 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.

import Foundation

struct Metadata: Codable {

let sourceUrl: URL?

init(sourceUrl: URL? = nil) {
self.sourceUrl = sourceUrl
}

init(contentsOf url: URL) throws {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
self = try decoder.decode(Metadata.self, from: data)
}

func write(to url: URL) throws {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try encoder.encode(self)
try data.write(to: url, options: .atomic)
}

}
9 changes: 9 additions & 0 deletions OpoLua/Model/Program.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ class Program {
return applicationMetadata?.uid3
}

var metadata: Metadata {
guard let systemFileSystem = fileSystem as? SystemFileSystem else {
return Metadata()
}
return systemFileSystem.metadata
}

lazy private var fileSystem: FileSystem = {
do {
return try FileManager.default.detectSystemFileSystem(for: url) ?? ObjectFileSystem(objectUrl: url)
Expand Down Expand Up @@ -436,6 +443,8 @@ extension Program: InterpreterThreadDelegate {
return fileSystem.guestPath(for: url)
}

// TODO: Result might be better as an actual result. Oh. That's a Tom Thing.
// TODO: Unclear to me whether this would be the right place to handle the error or not.
func interpreter(_ interpreter: InterpreterThread, didFinishWithResult result: Error?) {
DispatchQueue.main.sync {
interpreter.handler = nil
Expand Down
13 changes: 13 additions & 0 deletions OpoLua/Model/SystemFileSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ class SystemFileSystem: FileSystem {
self.rootUrl = rootUrl
}

var metadata: Metadata {
get {
return (try? Metadata(contentsOf: rootUrl.appendingPathComponent("manifest.json"))) ?? Metadata()
}
set {
do {
try newValue.write(to: rootUrl.appendingPathComponent("manifest.json"))
} catch {
print("Failed to save file system metadata with error \(error).")
}
}
}

func prepare() throws {
let fileManager = FileManager.default
try fileManager.createDirectory(at: rootUrl, withIntermediateDirectories: true)
Expand Down
9 changes: 3 additions & 6 deletions OpoLua/Utilities/RaiseGitHubIssueActivity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class RaiseGitHubIssueActivity: UIActivity {
return .action
}

let error: Error
let url: URL
var activityItems = [Any]()

override var activityTitle: String? {
Expand All @@ -41,8 +41,8 @@ class RaiseGitHubIssueActivity: UIActivity {
return UIActivity.ActivityType(rawValue: "org.opolua.action.raise-github-issue")
}

init(error: Error) {
self.error = error
init(url: URL) {
self.url = url
super.init()
}

Expand All @@ -62,9 +62,6 @@ class RaiseGitHubIssueActivity: UIActivity {
defer {
activityDidFinish(true)
}
guard let url = error.gitHubIssueUrl else {
return
}
UIApplication.shared.open(url)
}

Expand Down
5 changes: 3 additions & 2 deletions OpoLua/View Controllers/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,10 @@ extension BrowserViewController: PsionSoftwareIndexViewControllerDelegate {
psionSoftwareIndexViewController.dismiss(animated: true)
}

func psionSoftwareIndexViewController(psionSoftwareIndexViewController: PsionSoftwareIndexViewController, didSelectURL url: URL) {
func psionSoftwareIndexViewController(psionSoftwareIndexViewController: PsionSoftwareIndexViewController,
didSelectItem item: SoftwareIndexView.Item) {
psionSoftwareIndexViewController.dismiss(animated: true) {
AppDelegate.shared.install(url: url)
AppDelegate.shared.install(url: item.url, sourceUrl: item.sourceURL)
}
}

Expand Down
Loading

0 comments on commit dbdb062

Please sign in to comment.