diff --git a/CHANGELOG.md b/CHANGELOG.md
index b158d0f..d35e9c0 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,11 +10,25 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Refactor application.
+## [0.8.0] - 2021-09-02
+
+### Added
+
+- Develop additional `Finder extension` which allows to create a `hard links` for selected folders and files via contextual menu.
+
+### Changed
+
+- Change build os version to 10.10.
+
+### Fixed
+
+- Fix soft link replace with function.
+
## [0.7.0] - 2021-08-22
### Added
-- Added new classes `Path` for working with path's and creating relative path from specified directory.
+- Add new classes `Path` for working with path's and creating relative path from specified directory.
- Add unit-tests cases for the `Path` class.
### Changed
@@ -25,13 +39,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Changed
-- Changed the activity property of some menu items according to the rule:
+- Change the activity property of some menu items according to the rule:
- if no object was copied, then the menu items "Paste link to here" an "Move it here and replace with a link" are not active.
- if at least one object was not copied, then the menu items "Paste link to here" an "Move it here and replace with a link" are inactive.
### Added
-- Added cleaning clipboard after inserting links.
+- Add cleaning clipboard after inserting links.
## [0.5.0] - 2021-08-02
diff --git a/README.md b/README.md
index e09474a..6d58702 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,11 @@
The Quick Symlink is a `Finder extension` which provides a `contextual menu item` for the symbolic links creation on macOS.
-[![status](https://img.shields.io/badge/status-active-active?style=flat-square)](BADGES_GUIDE.md#status) [![version](https://img.shields.io/badge/version-0.6.0-informational?style=flat-square)](BADGES_GUIDE.md#version) [![oss lifecycle](https://img.shields.io/badge/oss_lifecycle-active-important?style=flat-square)](BADGES_GUIDE.md#oss-lifecycle) [![maintenance](https://img.shields.io/badge/maintenance-yes-informational?style=flat-square)](BADGES_GUIDE.md#maintenance) [![last release](https://img.shields.io/badge/last_release-August_22,_2021-informational?style=flat-square)](BADGES_GUIDE.md#release-date) [![last commit](https://img.shields.io/badge/last_commit-August_22,_2021-informational?style=flat-square)](BADGES_GUIDE.md#commit-date)
+[![status](https://img.shields.io/badge/status-active-active?style=flat-square)](BADGES_GUIDE.md#status) [![version](https://img.shields.io/badge/version-0.8.0-informational?style=flat-square)](BADGES_GUIDE.md#version) [![oss lifecycle](https://img.shields.io/badge/oss_lifecycle-active-important?style=flat-square)](BADGES_GUIDE.md#oss-lifecycle) [![maintenance](https://img.shields.io/badge/maintenance-yes-informational?style=flat-square)](BADGES_GUIDE.md#maintenance) [![last release](https://img.shields.io/badge/last_release-September_02,_2021-informational?style=flat-square)](BADGES_GUIDE.md#release-date) [![last commit](https://img.shields.io/badge/last_commit-September_02,_2021-informational?style=flat-square)](BADGES_GUIDE.md#commit-date)
[![license](https://img.shields.io/badge/license-MIT-informational?style=flat-square)](LICENSE) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg?style=flat-square)](CODE_OF_CONDUCT.md)
-[![platform](https://img.shields.io/badge/platform-OS_X_10.11+-important?style=flat-square)](https://en.wikipedia.org/wiki/Computing_platform)
+[![platform](https://img.shields.io/badge/platform-OS_X_10.10+-important?style=flat-square)](https://en.wikipedia.org/wiki/Computing_platform)
---
@@ -55,10 +55,14 @@ This GIF demonstrates how the `Quick Symlink` allows quite simple to copy files
## π Features
- Create a symbolic links in a several clicks via the context menu instead of the terminal promt:
- - Select files or folders and create symlink for them.
- - Copy files or folders and paste symlink somewhere.
+ - Select files or folders and create symlinks for them.
+ - Copy files or folders and paste symlinks somewhere.
- Copy files or folders, paste them somewhere, and replace them with symlinks.
+- Create a hard links in a several clicks via the context menu instead of the terminal promt:
+ - Select files or folders and create hard links for them.
+ - Copy files or folders and paste hard links somewhere.
+
### To Do
- For more information on an upcoming development, please read the [todo](TODO.md) list.
@@ -75,12 +79,12 @@ These instructions allow to get a copy of this project and run it on a local mac
Before using it, make sure that follows software are installed on the local machine:
-- **[OS X 10.11+](https://www.apple.com/ru/macos/what-is/)** - the operating system under which the extention is executing.
+- **[OS X 10.10+](https://www.apple.com/ru/macos/what-is/)** - the operating system under which the extention is executing.
If any of the listed programs is not installed, then it can be installed by instruction as described below.
-1. #### OS X 10.11+
- - Install macOS 10.11+ by [this](https://support.apple.com/ht201372) instruction.
+1. #### OS X 10.10+
+ - Install macOS 10.10+ by [this](https://support.apple.com/ht201372) instruction.
### Installing
@@ -105,7 +109,9 @@ In order to install it is quite simple to:
open quick-symlink.app
```
-4. Open up `System Preferences > Extensions` and enable the extension `quick-symlink`.
+4. Open up `System Preferences > Extensions` and enable the follows extensions:
+ 4.1. `quick-symlink-extension` - for the symlink actions.
+ 4.2. `hard-link-actions-extension` - for the hard link actions.
**Otherwise, it's possible to install and remove the extention using the actual extension bundled into the app.**
@@ -113,12 +119,14 @@ In order to install it is quite simple to:
```bash
pluginkit -a quick-symlink.app/Contents/PlugIns/quick-symlink-extension.appex/
+pluginkit -a quick-symlink.app/Contents/PlugIns/hard-link-action-extension.appex/
```
2. To remove it, run this:
```bash
pluginkit -r quick-symlink.app/Contents/PlugIns/quick-symlink-extension.appex/
+pluginkit -r quick-symlink.app/Contents/PlugIns/hard-link-action-extension.appex/
```
### Downloading
@@ -144,27 +152,44 @@ This tool allows to:
Create symlinks in the current directory
1. Select folders or files for which a symbolic link is needed.
2. Call the contextual menu by the right-clicking on selected.
-3. Select menu item `Quick Symlink --> Create symlink for`.
+3. Select menu item `Symlink actions --> Create symlink for`.
Create symlinks in another directory
1. Select folders or files for which a symbolic link is needed.
2. Call the contextual menu by the right-clicking on selected.
-3. Select menu item `Quick Symlink --> Copy path from here`.
+3. Select menu item `Symlink actions --> Copy path from here`.
4. Go to a destination folder.
5. Call the contextual menu by right-clicking on the filder.
-6. Select menu item `Quick Symlink --> Paste to here`.
+6. Select menu item `Symlink actions --> Paste to here`.
Replace objects with symbolic links
1. Select folders or files for which a symbolic link is needed.
2. Call the contextual menu by the right-clicking on selected.
-3. Select menu item `Quick Symlink --> Copy to clipboard`.
+3. Select menu item `Symlink actions --> Copy to clipboard`.
+4. Go to a destination folder.
+5. Call the contextual menu by right-clicking on the filder.
+6. Select menu item `Symlink actions --> Move it here and replace with a link`.
+
+
+
+ Create hard links in the current directory
+1. Select folders or files for which a symbolic link is needed.
+2. Call the contextual menu by the right-clicking on selected.
+3. Select menu item `Hard link actions --> Create symlink for`.
+
+
+
+ Create symlinks in another directory
+1. Select folders or files for which a symbolic link is needed.
+2. Call the contextual menu by the right-clicking on selected.
+3. Select menu item `Hard link actions --> Copy path from here`.
4. Go to a destination folder.
5. Call the contextual menu by right-clicking on the filder.
-6. Select menu item `Quick Symlink --> Move it here and replace with a link`.
+6. Select menu item `Hard link actions --> Paste to here`.
## π Built With
diff --git a/TODO.md b/TODO.md
index a3ffbc5..914d65f 100755
--- a/TODO.md
+++ b/TODO.md
@@ -7,7 +7,7 @@
- [x] Add the new menu item for creating symlink in a parent directory (parent for target objects).
- [x] Optional feature - use relative path instead absolute path in symlink target URL (if target and link located in one volume)
- [ ] Refactor code in `commons/*` part and add unit-tests
-- [ ] Develop additional `Finder extension` which allows to create a `hard links` for selected folders and files via contextual menu
+- [x] Develop additional `Finder extension` which allows to create a `hard links` for selected folders and files via contextual menu
- [ ] Develop the action panel for created symbolic links and hard lonks (in the app window):
- [ ] a) (if broken) process to browse finder for 'Find/fix missing target'
- [ ] b) Modify existing paths and symbolic link features
diff --git a/commons/QuickSymlinkActions/QuickSymlinkAction.swift b/commons/QuickSymlinkActions/QuickSymlinkAction.swift
deleted file mode 100644
index 12e81aa..0000000
--- a/commons/QuickSymlinkActions/QuickSymlinkAction.swift
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// QuickSymlinkAction.swift
-// quick-symlink
-//
-// Created by Alexander A. Kropotin on 15/07/2021.
-// Copyright Β© 2021 Alexander A. Kropotin. All rights reserved.
-//
-
-import Foundation
-
-public protocol QuickSymlinkAction {
-
- func execute();
-}
-
-internal extension QuickSymlinkAction {
-
- internal func getTargetPath(_ from: URL!, to: URL!) -> URL! {
- let originSourceName = from.absoluteURL.deletingPathExtension().lastPathComponent;
- let fileType = from.absoluteURL.pathExtension;
-
- var fileExtention = fileType;
- if !fileType.isEmpty {
- fileExtention = ".\(fileType)"
- }
-
- var fileName = "\(originSourceName)\(fileExtention)";
- var counter = 1
- var targetPath = to;
- targetPath = targetPath?.appendingPathComponent(fileName);
-
- while FileManager.default.fileExists(atPath: (targetPath?.path)!) {
- fileName = "\(originSourceName)-\(counter)\(fileExtention)";
- counter += 1;
- targetPath = to.appendingPathComponent(fileName);
- }
-
- return targetPath!;
- }
-}
diff --git a/commons/link/FileLinkManager.swift b/commons/link/FileLinkManager.swift
new file mode 100644
index 0000000..359e268
--- /dev/null
+++ b/commons/link/FileLinkManager.swift
@@ -0,0 +1,89 @@
+//
+// FileManagerAdapter.swift
+// quick-symlink
+//
+// Created by Alexander A. Kropotin on 01/09/2021.
+// Copyright Β© 2021 Alexander A. Kropotin. All rights reserved.
+//
+
+import Foundation
+import FinderSync
+
+public protocol FileLinkManager {
+
+ func linkWith(of: URL!, with: URL!);
+
+ func replaceWith(of: URL!, with: URL!);
+}
+
+public extension FileLinkManager {
+
+ public func getTargetPath(_ from: URL!, to: URL!) -> URL! {
+ let originSourceName = from.absoluteURL.deletingPathExtension().lastPathComponent;
+ let fileType = from.absoluteURL.pathExtension;
+
+ var fileExtention = fileType;
+ if !fileType.isEmpty {
+ fileExtention = ".\(fileType)"
+ }
+
+ var fileName = "\(originSourceName)\(fileExtention)";
+ var counter = 1
+ var targetPath = to;
+ targetPath = targetPath?.appendingPathComponent(fileName);
+
+ while FileManager.default.fileExists(atPath: (targetPath?.path)!) {
+ fileName = "\(originSourceName)-\(counter)\(fileExtention)";
+ counter += 1;
+ targetPath = to.appendingPathComponent(fileName);
+ }
+
+ return targetPath!;
+ }
+}
+
+public class SoftLinkManager: FileLinkManager {
+
+ public func linkWith(of: URL!, with: URL!) {
+ do {
+ try FileManager.default.createSymbolicLink(at: with!, withDestinationURL: ResourcePath.of(url: of).relativize(to: ResourcePath.of(url: with?.deletingLastPathComponent())).toUrl()!);
+ } catch let error as NSError {
+ NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
+ }
+ }
+
+ public func replaceWith(of: URL!, with: URL!) {
+ do {
+ //FIXME: Add checking for existance of file & resolving this case with symply pastle link
+ try FileManager.default.moveItem(at: of, to: with);
+ try FileManager.default.createSymbolicLink(at: of, withDestinationURL: ResourcePath.of(url: with).relativize(to: ResourcePath.of(url: of.deletingLastPathComponent())).toUrl()!);
+ } catch let error as NSError {
+ NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
+ }
+ }
+}
+
+public class HardLinkManager: FileLinkManager {
+
+ public func linkWith(of: URL!, with: URL!) {
+
+ let pasteboard = NSPasteboard.general;
+ pasteboard.declareTypes([NSPasteboard.PasteboardType.string], owner: nil);
+
+ do {
+ try FileManager.default.linkItem(at: of, to: with);
+
+ } catch let error as NSError {
+ NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
+ }
+ }
+
+ public func replaceWith(of: URL!, with: URL!) {
+ do {
+ try FileManager.default.moveItem(at: of, to: with);
+ try FileManager.default.linkItem(at: with, to: of);
+ } catch let error as NSError {
+ NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
+ }
+ }
+}
diff --git a/commons/QuickSymlinkActions/CopyPathAction.swift b/commons/link/action/CopyPathAction.swift
similarity index 100%
rename from commons/QuickSymlinkActions/CopyPathAction.swift
rename to commons/link/action/CopyPathAction.swift
diff --git a/commons/QuickSymlinkActions/CreateLinkAction.swift b/commons/link/action/CreateLinkAction.swift
similarity index 57%
rename from commons/QuickSymlinkActions/CreateLinkAction.swift
rename to commons/link/action/CreateLinkAction.swift
index ac97835..2dcffed 100644
--- a/commons/QuickSymlinkActions/CreateLinkAction.swift
+++ b/commons/link/action/CreateLinkAction.swift
@@ -13,8 +13,11 @@ public class CreateLinkAction: QuickSymlinkAction {
private var finderController: FIFinderSyncController;
- public init() {
+ private var fileLinkManager: FileLinkManager;
+
+ public init(fileLinkManager: FileLinkManager!) {
self.finderController = FIFinderSyncController.default();
+ self.fileLinkManager = fileLinkManager;
}
public func execute() {
@@ -26,14 +29,8 @@ public class CreateLinkAction: QuickSymlinkAction {
}
for path in target {
- let targetPath = self.getTargetPath(path, to: path.deletingLastPathComponent());
-
- do {
- try FileManager.default.createSymbolicLink(at: targetPath!, withDestinationURL: ResourcePath.of(url: path).relativize(to: ResourcePath.of(url: targetPath?.deletingLastPathComponent())).toUrl()!);
- } catch let error as NSError {
- NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
- }
+ let targetPath = self.fileLinkManager.getTargetPath(path, to: path.deletingLastPathComponent());
+ self.fileLinkManager.linkWith(of: path, with: targetPath);
}
}
}
-
diff --git a/commons/QuickSymlinkActions/PasteLinkAction.swift b/commons/link/action/PasteLinkAction.swift
similarity index 69%
rename from commons/QuickSymlinkActions/PasteLinkAction.swift
rename to commons/link/action/PasteLinkAction.swift
index 991fbbe..aee04bb 100644
--- a/commons/QuickSymlinkActions/PasteLinkAction.swift
+++ b/commons/link/action/PasteLinkAction.swift
@@ -13,8 +13,11 @@ public class PasteLinkAction: QuickSymlinkAction {
private var finderController: FIFinderSyncController;
- public init() {
+ private var fileLinkManager: FileLinkManager;
+
+ public init(fileLinkManager: FileLinkManager!) {
self.finderController = FIFinderSyncController.default();
+ self.fileLinkManager = fileLinkManager;
}
public func execute() {
@@ -35,13 +38,8 @@ public class PasteLinkAction: QuickSymlinkAction {
let paths = pathsFromClipboard.components(separatedBy: ";");
for path in paths {
let pathUrl = URL(fileURLWithPath: path);
- let targetPath = self.getTargetPath(pathUrl, to: target);
-
- do {
- try FileManager.default.createSymbolicLink(at: targetPath!, withDestinationURL: ResourcePath.of(url: pathUrl).relativize(to: ResourcePath.of(url: targetPath?.deletingLastPathComponent())).toUrl()!);
- } catch let error as NSError {
- NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
- }
+ let targetPath = self.fileLinkManager.getTargetPath(pathUrl, to: target);
+ self.fileLinkManager.linkWith(of: pathUrl, with: targetPath);
}
}
}
diff --git a/commons/link/action/QuickSymlinkAction.swift b/commons/link/action/QuickSymlinkAction.swift
new file mode 100644
index 0000000..2b99d99
--- /dev/null
+++ b/commons/link/action/QuickSymlinkAction.swift
@@ -0,0 +1,14 @@
+//
+// QuickSymlinkAction.swift
+// quick-symlink
+//
+// Created by Alexander A. Kropotin on 15/07/2021.
+// Copyright Β© 2021 Alexander A. Kropotin. All rights reserved.
+//
+
+import Foundation
+
+public protocol QuickSymlinkAction {
+
+ func execute();
+}
diff --git a/commons/QuickSymlinkActions/ReplaceWithLinkAction.swift b/commons/link/action/ReplaceWithLinkAction.swift
similarity index 66%
rename from commons/QuickSymlinkActions/ReplaceWithLinkAction.swift
rename to commons/link/action/ReplaceWithLinkAction.swift
index d2a9c1b..f852cb8 100644
--- a/commons/QuickSymlinkActions/ReplaceWithLinkAction.swift
+++ b/commons/link/action/ReplaceWithLinkAction.swift
@@ -13,8 +13,11 @@ public class ReplaceWithLinkAction: QuickSymlinkAction {
private var finderController: FIFinderSyncController;
- public init() {
+ private var fileLinkManager: FileLinkManager;
+
+ public init(fileLinkManager: FileLinkManager!) {
self.finderController = FIFinderSyncController.default();
+ self.fileLinkManager = fileLinkManager;
}
public func execute() {
@@ -35,14 +38,8 @@ public class ReplaceWithLinkAction: QuickSymlinkAction {
let paths = pathsFromClipboard.components(separatedBy: ";");
for path in paths {
let pathUrl = URL(fileURLWithPath: path);
- let targetPath = self.getTargetPath(pathUrl, to: target);
-
- do {
- try FileManager.default.moveItem(at: pathUrl, to: targetPath!);
- try FileManager.default.createSymbolicLink(at: pathUrl, withDestinationURL: ResourcePath.of(url: targetPath).relativize(to: ResourcePath.of(url: pathUrl.deletingLastPathComponent())).toUrl()!);
- } catch let error as NSError {
- NSLog("FileManager.createSymbolicLink() failed to create file: %@", error.description as NSString);
- }
+ let targetPath = self.fileLinkManager.getTargetPath(pathUrl, to: target);
+ self.fileLinkManager.replaceWith(of: pathUrl, with: targetPath);
}
}
}
diff --git a/commons/FileSystem/Path.swift b/commons/path/Path.swift
similarity index 100%
rename from commons/FileSystem/Path.swift
rename to commons/path/Path.swift
diff --git a/commons/FileSystem/ResourcePath.swift b/commons/path/ResourcePath.swift
similarity index 96%
rename from commons/FileSystem/ResourcePath.swift
rename to commons/path/ResourcePath.swift
index fa4fb6c..f05468c 100644
--- a/commons/FileSystem/ResourcePath.swift
+++ b/commons/path/ResourcePath.swift
@@ -50,8 +50,6 @@ public class ResourcePath: Path {
destinationPath.appendPathComponent(pathFragment);
}
- //pathFragments!.append(contentsOf: targetPathFragments!);
-
return ResourcePath.of(url: destinationPath);
}
diff --git a/hard-link-action-extension/Assets.xcassets/Contents.json b/hard-link-action-extension/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/hard-link-action-extension/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/Contents.json b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/Contents.json
new file mode 100644
index 0000000..1553d71
--- /dev/null
+++ b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/Contents.json
@@ -0,0 +1,33 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "quick-symlink-app-icon-28.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "quick-symlink-app-icon-56.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "quick-symlink-app-icon-84.png",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "mac",
+ "filename" : "quick-symlink-app-icon-29.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "filename" : "quick-symlink-app-icon-57.png",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-28.png b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-28.png
new file mode 100644
index 0000000..84841b0
Binary files /dev/null and b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-28.png differ
diff --git a/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-29.png b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-29.png
new file mode 100644
index 0000000..84841b0
Binary files /dev/null and b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-29.png differ
diff --git a/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-56.png b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-56.png
new file mode 100644
index 0000000..be4fb4c
Binary files /dev/null and b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-56.png differ
diff --git a/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-57.png b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-57.png
new file mode 100644
index 0000000..be4fb4c
Binary files /dev/null and b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-57.png differ
diff --git a/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-84.png b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-84.png
new file mode 100644
index 0000000..7dbe657
Binary files /dev/null and b/hard-link-action-extension/Assets.xcassets/quick-symlink-toolbar-item-image.imageset/quick-symlink-app-icon-84.png differ
diff --git a/hard-link-action-extension/FinderSync.swift b/hard-link-action-extension/FinderSync.swift
new file mode 100644
index 0000000..6320399
--- /dev/null
+++ b/hard-link-action-extension/FinderSync.swift
@@ -0,0 +1,127 @@
+//
+// FinderSync.swift
+// hard-link-action-extension
+//
+// Created by Alexander A. Kropotin on 02/09/2021.
+// Copyright Β© 2021 Alexander A. Kropotin. All rights reserved.
+//
+
+import Cocoa
+import FinderSync
+
+class FinderSync: FIFinderSync {
+
+ let quickSymlinkToolbarItemImage = NSImage(named:NSImage.Name(rawValue: "quick-symlink-toolbar-item-image"));
+
+ let copyPathAction = CopyPathAction.init();
+ let pasteLinkAction = PasteLinkAction.init(fileLinkManager: HardLinkManager.init());
+ let createSymlink = CreateLinkAction.init(fileLinkManager: HardLinkManager.init());
+
+ override init() {
+ super.init()
+
+ NSLog("FinderSync() launched from %@", Bundle.main.bundlePath as NSString)
+
+ // Set up the directory we are syncing.
+ let finderSync = FIFinderSyncController.default();
+
+ // Shared group preferences required
+ _ = UserDefaults.init(suiteName: "org.ololx.quick-symlink")
+
+ if let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil,
+ options: .skipHiddenVolumes) {
+ finderSync.directoryURLs = Set(mountedVolumes);
+ }
+
+ let notificationCenter = NSWorkspace.shared.notificationCenter
+ notificationCenter.addObserver(forName: NSWorkspace.didMountNotification, object: nil, queue: .main) {
+ (notification) in
+ if let volumeURL = notification.userInfo?[NSWorkspace.volumeURLUserInfoKey] as? URL {
+ finderSync.directoryURLs.insert(volumeURL);
+ }
+ }
+ }
+
+ // MARK: - Primary Finder Sync protocol methods
+
+ override func beginObservingDirectory(at url: URL) {
+ // The user is now seeing the container's contents.
+ // If they see it in more than one view at a time, we're only told once.
+ NSLog("beginObservingDirectoryAtURL: %@", url.path as NSString)
+ }
+
+
+ override func endObservingDirectory(at url: URL) {
+ // The user is no longer seeing the container's contents.
+ NSLog("endObservingDirectoryAtURL: %@", url.path as NSString)
+ }
+
+ // MARK: - Menu and toolbar item support
+
+ override var toolbarItemName: String {
+ return NSLocalizedString("HARD_LINK_ACTIONS_EXTENTION_NAME", comment: "");
+ }
+
+ override var toolbarItemToolTip: String {
+ return NSLocalizedString("HARD_LINK_ACTIONS_EXTENTION_TOOL_TIP", comment: "");
+ }
+
+ override var toolbarItemImage: NSImage {
+ return quickSymlinkToolbarItemImage!;
+ }
+
+ override func menu(for menuKind: FIMenuKind) -> NSMenu {
+ // Produce a menu for the extension (to be shown when right clicking a folder in Finder)
+ let quickSymlinkMenu = NSMenu(title: "");
+ quickSymlinkMenu.addItem(
+ withTitle: NSLocalizedString("CREATE_LINK_ACTION_NAME", comment: ""),
+ action: #selector(createSymlink(_:)),
+ keyEquivalent: ""
+ );
+
+ quickSymlinkMenu.addItem(
+ withTitle: NSLocalizedString("COPY_PATH_ACTION_NAME", comment: ""),
+ action: #selector(copyPathToClipboard(_:)),
+ keyEquivalent: ""
+ );
+
+ let pastleSymlinkFromClipboardMenuItem = NSMenuItem.init(
+ title: NSLocalizedString("PASTE_LINK_ACTION_NAME", comment: ""),
+ action: #selector(pastleSymlinkFromClipboard(_:)),
+ keyEquivalent: ""
+ );
+ quickSymlinkMenu.addItem(pastleSymlinkFromClipboardMenuItem);
+
+ if (NSPasteboard.init(name: NSPasteboard.Name.init(rawValue: "qs")).string(forType: NSPasteboard.PasteboardType.string) ?? "").isEmpty {
+ pastleSymlinkFromClipboardMenuItem.isEnabled = false;
+ }
+
+ if menuKind.rawValue == 3 {
+ return quickSymlinkMenu;
+ } else {
+ let quickSymLinkMainMenu = NSMenu(title: "");
+ let quickSymlinkMenuItem = NSMenuItem(
+ title: NSLocalizedString("HARD_LINK_ACTIONS_EXTENTION_NAME", comment: ""),
+ action: nil,
+ keyEquivalent: ""
+ );
+ quickSymLinkMainMenu.setSubmenu(quickSymlinkMenu, for: quickSymlinkMenuItem);
+ quickSymLinkMainMenu.addItem(quickSymlinkMenuItem);
+
+ return quickSymLinkMainMenu;
+ }
+ }
+
+ @IBAction func copyPathToClipboard(_ sender: AnyObject?) {
+ self.copyPathAction.execute();
+ }
+
+ @IBAction func pastleSymlinkFromClipboard(_ sender: AnyObject?) {
+ self.pasteLinkAction.execute();
+ }
+
+ @IBAction func createSymlink(_ sender: AnyObject?) {
+ self.createSymlink.execute();
+ }
+}
+
diff --git a/hard-link-action-extension/Info.plist b/hard-link-action-extension/Info.plist
new file mode 100644
index 0000000..e03c840
--- /dev/null
+++ b/hard-link-action-extension/Info.plist
@@ -0,0 +1,41 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ hard-link-action-extension
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ $(MACOSX_DEPLOYMENT_TARGET)
+ LSUIElement
+
+ NSExtension
+
+ NSExtensionAttributes
+
+ NSExtensionPointIdentifier
+ com.apple.FinderSync
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).FinderSync
+
+ NSHumanReadableCopyright
+ Copyright Β© 2021 Alexander A. Kropotin. All rights reserved.
+ NSPrincipalClass
+ NSApplication
+
+
diff --git a/hard-link-action-extension/hard-link-action-extension.entitlements b/hard-link-action-extension/hard-link-action-extension.entitlements
new file mode 100644
index 0000000..604e60f
--- /dev/null
+++ b/hard-link-action-extension/hard-link-action-extension.entitlements
@@ -0,0 +1,20 @@
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.folders.user-selected.read-write
+
+ com.apple.security.files.user-selected.read-write
+
+ com.apple.security.temporary-exception.files.absolute-path.read-write
+
+ /
+
+ com.apple.security.temporary-exception.files.home-relative-path.read-write
+
+ /
+
+
+
diff --git a/quick-symlink-extension/Base.lproj/Localizable.strings b/quick-symlink-extension/Base.lproj/Localizable.strings
index 2a48615..1de47e6 100644
--- a/quick-symlink-extension/Base.lproj/Localizable.strings
+++ b/quick-symlink-extension/Base.lproj/Localizable.strings
@@ -7,10 +7,16 @@
*/
/* Class = "NSMenuItem"; */
-"EXTENTION_NAME" = "Quick Symlink";
+"SOFT_LINK_ACTIONS_EXTENTION_NAME" = "Soft link actions";
/* Class = "NSMenuItem"; */
-"EXTENTION_TOOL_TIP" = "Create symbolic links for selected files and folders";
+"SOFT_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Create symbolic links for selected files and folders";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_NAME" = "Hard link actions";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Create hard links for selected files and folders";
/* Class = "NSMenuItem"; */
"COPY_PATH_ACTION_NAME" = "Copy path from here";
diff --git a/quick-symlink-extension/FinderSync.swift b/quick-symlink-extension/FinderSync.swift
index 5b6626d..fe10be9 100644
--- a/quick-symlink-extension/FinderSync.swift
+++ b/quick-symlink-extension/FinderSync.swift
@@ -13,9 +13,9 @@ class FinderSync: FIFinderSync {
let quickSymlinkToolbarItemImage = NSImage(named:NSImage.Name(rawValue: "quick-symlink-toolbar-item-image"));
let copyPathAction = CopyPathAction.init();
- let pasteLinkAction = PasteLinkAction.init();
- let replaceWithLinkAction = ReplaceWithLinkAction.init();
- let createSymlink = CreateLinkAction.init();
+ let pasteLinkAction = PasteLinkAction.init(fileLinkManager: SoftLinkManager.init());
+ let replaceWithLinkAction = ReplaceWithLinkAction.init(fileLinkManager: SoftLinkManager.init());
+ let createSymlink = CreateLinkAction.init(fileLinkManager: SoftLinkManager.init());
override init() {
super.init()
@@ -59,11 +59,11 @@ class FinderSync: FIFinderSync {
// MARK: - Menu and toolbar item support
override var toolbarItemName: String {
- return NSLocalizedString("EXTENTION_NAME", comment: "");
+ return NSLocalizedString("SOFT_LINK_ACTIONS_EXTENTION_NAME", comment: "");
}
override var toolbarItemToolTip: String {
- return NSLocalizedString("EXTENTION_TOOL_TIP", comment: "");
+ return NSLocalizedString("SOFT_LINK_ACTIONS_EXTENTION_TOOL_TIP", comment: "");
}
override var toolbarItemImage: NSImage {
@@ -109,7 +109,7 @@ class FinderSync: FIFinderSync {
} else {
let quickSymLinkMainMenu = NSMenu(title: "");
let quickSymlinkMenuItem = NSMenuItem(
- title: NSLocalizedString("EXTENTION_NAME", comment: ""),
+ title: NSLocalizedString("SOFT_LINK_ACTIONS_EXTENTION_NAME", comment: ""),
action: nil,
keyEquivalent: ""
);
diff --git a/quick-symlink-extension/Info.plist b/quick-symlink-extension/Info.plist
index 8f22540..99c4c3b 100644
--- a/quick-symlink-extension/Info.plist
+++ b/quick-symlink-extension/Info.plist
@@ -3,7 +3,7 @@
CFBundleDevelopmentRegion
- en_GB
+ $(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
quick-symlink-extension
CFBundleExecutable
diff --git a/quick-symlink-extension/en-GB.lproj/Localizable.strings b/quick-symlink-extension/en-GB.lproj/Localizable.strings
index 2a48615..1de47e6 100644
--- a/quick-symlink-extension/en-GB.lproj/Localizable.strings
+++ b/quick-symlink-extension/en-GB.lproj/Localizable.strings
@@ -7,10 +7,16 @@
*/
/* Class = "NSMenuItem"; */
-"EXTENTION_NAME" = "Quick Symlink";
+"SOFT_LINK_ACTIONS_EXTENTION_NAME" = "Soft link actions";
/* Class = "NSMenuItem"; */
-"EXTENTION_TOOL_TIP" = "Create symbolic links for selected files and folders";
+"SOFT_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Create symbolic links for selected files and folders";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_NAME" = "Hard link actions";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Create hard links for selected files and folders";
/* Class = "NSMenuItem"; */
"COPY_PATH_ACTION_NAME" = "Copy path from here";
diff --git a/quick-symlink-extension/en.lproj/Localizable.strings b/quick-symlink-extension/en.lproj/Localizable.strings
index 2a48615..1de47e6 100644
--- a/quick-symlink-extension/en.lproj/Localizable.strings
+++ b/quick-symlink-extension/en.lproj/Localizable.strings
@@ -7,10 +7,16 @@
*/
/* Class = "NSMenuItem"; */
-"EXTENTION_NAME" = "Quick Symlink";
+"SOFT_LINK_ACTIONS_EXTENTION_NAME" = "Soft link actions";
/* Class = "NSMenuItem"; */
-"EXTENTION_TOOL_TIP" = "Create symbolic links for selected files and folders";
+"SOFT_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Create symbolic links for selected files and folders";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_NAME" = "Hard link actions";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Create hard links for selected files and folders";
/* Class = "NSMenuItem"; */
"COPY_PATH_ACTION_NAME" = "Copy path from here";
diff --git a/quick-symlink-extension/quick_symlink_extension.entitlements b/quick-symlink-extension/quick_symlink_extension.entitlements
deleted file mode 100644
index 0c67376..0000000
--- a/quick-symlink-extension/quick_symlink_extension.entitlements
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/quick-symlink-extension/ru.lproj/Localizable.strings b/quick-symlink-extension/ru.lproj/Localizable.strings
index 361f830..18900c5 100644
--- a/quick-symlink-extension/ru.lproj/Localizable.strings
+++ b/quick-symlink-extension/ru.lproj/Localizable.strings
@@ -7,10 +7,16 @@
*/
/* Class = "NSMenuItem"; */
-"EXTENTION_NAME" = "ΠΡΡΡΡΡΠΉ ΡΠΈΠΌΠ»ΠΈΠ½ΠΊ";
+"SOFT_LINK_ACTIONS_EXTENTION_NAME" = "ΠΠ΅ΠΉΡΡΠ²ΠΈΡ Ρ ΡΠΈΠΌΠ»ΠΈΠ½ΠΊΠ°ΠΌΠΈ";
/* Class = "NSMenuItem"; */
-"EXTENTION_TOOL_TIP" = "Π‘ΠΎΠ·Π΄Π°ΡΡ ΡΠΈΠΌΠ²ΠΎΠ»ΡΠ½ΡΠ΅ ΡΡΡΠ»ΠΊΠΈ Π΄Π»Ρ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ
ΡΠ°ΠΉΠ»ΠΎΠ² ΠΈ ΠΏΠ°ΠΏΠΎΠΊ";
+"SOFT_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Π‘ΠΎΠ·Π΄Π°ΡΡ ΡΠΈΠΌΠ²ΠΎΠ»ΡΠ½ΡΠ΅ ΡΡΡΠ»ΠΊΠΈ Π΄Π»Ρ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ
ΡΠ°ΠΉΠ»ΠΎΠ² ΠΈ ΠΏΠ°ΠΏΠΎΠΊ";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_NAME" = "ΠΠ΅ΠΉΡΡΠ²ΠΈΡ Ρ ΠΏΡΠ΅Π²Π΄ΠΎΠ½ΠΈΠΌΠ°ΠΌΠΈ";
+
+/* Class = "NSMenuItem"; */
+"HARD_LINK_ACTIONS_EXTENTION_TOOL_TIP" = "Π‘ΠΎΠ·Π΄Π°ΡΡ ΠΏΡΠ΅Π²Π΄ΠΎΠ½ΠΈΠΌΡ Π΄Π»Ρ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ
ΡΠ°ΠΉΠ»ΠΎΠ² ΠΈ ΠΏΠ°ΠΏΠΎΠΊ";
/* Class = "NSMenuItem"; */
"COPY_PATH_ACTION_NAME" = "Π‘ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°ΡΡ ΠΏΡΡΡ ΠΎΡΡΡΠ΄Π°";
diff --git a/quick-symlink.xcodeproj/project.pbxproj b/quick-symlink.xcodeproj/project.pbxproj
index 1de801c..9853a2e 100644
--- a/quick-symlink.xcodeproj/project.pbxproj
+++ b/quick-symlink.xcodeproj/project.pbxproj
@@ -26,12 +26,26 @@
A30D4A4D26A0C18B00BA775B /* QuickSymlinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9BE26A0B200004FBF0F /* QuickSymlinkAction.swift */; };
A316477726B7B403001DD969 /* CreateLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A316477626B7B403001DD969 /* CreateLinkAction.swift */; };
A316477826B7B403001DD969 /* CreateLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A316477626B7B403001DD969 /* CreateLinkAction.swift */; };
+ A31904A426E104FA00D7F69D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A31904A326E104FA00D7F69D /* Assets.xcassets */; };
A32EE8E0265D4D05008648AA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A32EE8DF265D4D05008648AA /* Assets.xcassets */; };
A345C9BF26A0B200004FBF0F /* QuickSymlinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9BE26A0B200004FBF0F /* QuickSymlinkAction.swift */; };
A345C9C226A0B30F004FBF0F /* CopyPathAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9C126A0B30F004FBF0F /* CopyPathAction.swift */; };
A345C9C526A0B49C004FBF0F /* PasteLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9C426A0B49C004FBF0F /* PasteLinkAction.swift */; };
A345C9C826A0B552004FBF0F /* ReplaceWithLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9C726A0B552004FBF0F /* ReplaceWithLinkAction.swift */; };
+ A36F9B0626DFAC27009E95CE /* FileLinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A36F9B0526DFAC27009E95CE /* FileLinkManager.swift */; };
+ A36F9B0726DFB127009E95CE /* FileLinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A36F9B0526DFAC27009E95CE /* FileLinkManager.swift */; };
A3D93EB526A09B5A004E068D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A3D93EB726A09B5A004E068D /* Localizable.strings */; };
+ A3E4D35526E0FD2900C9F175 /* FinderSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3E4D35426E0FD2900C9F175 /* FinderSync.swift */; };
+ A3E4D35A26E0FD2900C9F175 /* hard-link-action-extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A3E4D35226E0FD2900C9F175 /* hard-link-action-extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ A3E4D35E26E0FEE700C9F175 /* FileLinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A36F9B0526DFAC27009E95CE /* FileLinkManager.swift */; };
+ A3E4D35F26E0FEEA00C9F175 /* QuickSymlinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9BE26A0B200004FBF0F /* QuickSymlinkAction.swift */; };
+ A3E4D36026E0FEED00C9F175 /* CopyPathAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9C126A0B30F004FBF0F /* CopyPathAction.swift */; };
+ A3E4D36126E0FEEF00C9F175 /* PasteLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9C426A0B49C004FBF0F /* PasteLinkAction.swift */; };
+ A3E4D36226E0FEF200C9F175 /* ReplaceWithLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A345C9C726A0B552004FBF0F /* ReplaceWithLinkAction.swift */; };
+ A3E4D36326E0FEF400C9F175 /* CreateLinkAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A316477626B7B403001DD969 /* CreateLinkAction.swift */; };
+ A3E4D36426E0FF8100C9F175 /* ResourcePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = A307B41926D22116002EEF58 /* ResourcePath.swift */; };
+ A3E4D36526E0FF8600C9F175 /* Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = A307B41626D21E39002EEF58 /* Path.swift */; };
+ A3E4D36626E101B000C9F175 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A3D93EB726A09B5A004E068D /* Localizable.strings */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -49,6 +63,13 @@
remoteGlobalIDString = A30B9ABD265CA68900ACAA63;
remoteInfo = "quick-symlink-extension";
};
+ A3E4D35826E0FD2900C9F175 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = A30B9A9F265CA63300ACAA63 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = A3E4D35126E0FD2900C9F175;
+ remoteInfo = "hard-link-action-extension";
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -58,6 +79,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
+ A3E4D35A26E0FD2900C9F175 /* hard-link-action-extension.appex in Embed App Extensions */,
A30B9AC6265CA68900ACAA63 /* quick-symlink-extension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
@@ -81,14 +103,15 @@
A30B9ABE265CA68900ACAA63 /* quick-symlink-extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "quick-symlink-extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
A30B9AC0265CA68900ACAA63 /* FinderSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinderSync.swift; sourceTree = ""; };
A30B9AC2265CA68900ACAA63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- A30B9AC3265CA68900ACAA63 /* quick_symlink_extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = quick_symlink_extension.entitlements; sourceTree = ""; };
A30B9ACB265CA78600ACAA63 /* quick-symlink-extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "quick-symlink-extension.entitlements"; sourceTree = ""; };
A316477626B7B403001DD969 /* CreateLinkAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateLinkAction.swift; sourceTree = ""; };
+ A31904A326E104FA00D7F69D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
A32EE8DF265D4D05008648AA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
A345C9BE26A0B200004FBF0F /* QuickSymlinkAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSymlinkAction.swift; sourceTree = ""; };
A345C9C126A0B30F004FBF0F /* CopyPathAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyPathAction.swift; sourceTree = ""; };
A345C9C426A0B49C004FBF0F /* PasteLinkAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteLinkAction.swift; sourceTree = ""; };
A345C9C726A0B552004FBF0F /* ReplaceWithLinkAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplaceWithLinkAction.swift; sourceTree = ""; };
+ A36F9B0526DFAC27009E95CE /* FileLinkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileLinkManager.swift; sourceTree = ""; };
A3D93EA426A08EDF004E068D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Main.strings; sourceTree = ""; };
A3D93EA826A0904F004E068D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = ""; };
A3D93EA926A09053004E068D /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/Main.strings"; sourceTree = ""; };
@@ -96,6 +119,10 @@
A3D93EB826A09B61004E068D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; };
A3D93EB926A09B72004E068D /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/Localizable.strings"; sourceTree = ""; };
A3D93EBA26A09B73004E068D /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; };
+ A3E4D35226E0FD2900C9F175 /* hard-link-action-extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "hard-link-action-extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
+ A3E4D35426E0FD2900C9F175 /* FinderSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinderSync.swift; sourceTree = ""; };
+ A3E4D35626E0FD2900C9F175 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ A3E4D35726E0FD2900C9F175 /* hard-link-action-extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "hard-link-action-extension.entitlements"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -120,10 +147,17 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ A3E4D34F26E0FD2900C9F175 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- A307B41426D21DBE002EEF58 /* QuickSymlinkActions */ = {
+ A307B41426D21DBE002EEF58 /* action */ = {
isa = PBXGroup;
children = (
A316477626B7B403001DD969 /* CreateLinkAction.swift */,
@@ -132,16 +166,16 @@
A345C9C126A0B30F004FBF0F /* CopyPathAction.swift */,
A345C9BE26A0B200004FBF0F /* QuickSymlinkAction.swift */,
);
- path = QuickSymlinkActions;
+ path = action;
sourceTree = "";
};
- A307B41526D21E23002EEF58 /* FileSystem */ = {
+ A307B41526D21E23002EEF58 /* path */ = {
isa = PBXGroup;
children = (
A307B41626D21E39002EEF58 /* Path.swift */,
A307B41926D22116002EEF58 /* ResourcePath.swift */,
);
- path = FileSystem;
+ path = path;
sourceTree = "";
};
A307B42526D255FB002EEF58 /* quick-symlink-tests */ = {
@@ -161,6 +195,7 @@
A30B9AA9265CA63300ACAA63 /* quick-symlink */,
A30B9ABF265CA68900ACAA63 /* quick-symlink-extension */,
A307B42526D255FB002EEF58 /* quick-symlink-tests */,
+ A3E4D35326E0FD2900C9F175 /* hard-link-action-extension */,
A30B9AA8265CA63300ACAA63 /* Products */,
);
sourceTree = "";
@@ -171,6 +206,7 @@
A30B9AA7265CA63300ACAA63 /* quick-symlink.app */,
A30B9ABE265CA68900ACAA63 /* quick-symlink-extension.appex */,
A307B42426D255FB002EEF58 /* quick-symlink-tests.xctest */,
+ A3E4D35226E0FD2900C9F175 /* hard-link-action-extension.appex */,
);
name = Products;
sourceTree = "";
@@ -195,7 +231,6 @@
A30B9AC0265CA68900ACAA63 /* FinderSync.swift */,
A32EE8DF265D4D05008648AA /* Assets.xcassets */,
A30B9AC2265CA68900ACAA63 /* Info.plist */,
- A30B9AC3265CA68900ACAA63 /* quick_symlink_extension.entitlements */,
);
path = "quick-symlink-extension";
sourceTree = "";
@@ -203,12 +238,32 @@
A345C9BD26A0B12C004FBF0F /* commons */ = {
isa = PBXGroup;
children = (
- A307B41526D21E23002EEF58 /* FileSystem */,
- A307B41426D21DBE002EEF58 /* QuickSymlinkActions */,
+ A36F9B0426DFAA4B009E95CE /* link */,
+ A307B41526D21E23002EEF58 /* path */,
);
path = commons;
sourceTree = "";
};
+ A36F9B0426DFAA4B009E95CE /* link */ = {
+ isa = PBXGroup;
+ children = (
+ A307B41426D21DBE002EEF58 /* action */,
+ A36F9B0526DFAC27009E95CE /* FileLinkManager.swift */,
+ );
+ path = link;
+ sourceTree = "";
+ };
+ A3E4D35326E0FD2900C9F175 /* hard-link-action-extension */ = {
+ isa = PBXGroup;
+ children = (
+ A3E4D35426E0FD2900C9F175 /* FinderSync.swift */,
+ A3E4D35626E0FD2900C9F175 /* Info.plist */,
+ A3E4D35726E0FD2900C9F175 /* hard-link-action-extension.entitlements */,
+ A31904A326E104FA00D7F69D /* Assets.xcassets */,
+ );
+ path = "hard-link-action-extension";
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -243,6 +298,7 @@
);
dependencies = (
A30B9AC5265CA68900ACAA63 /* PBXTargetDependency */,
+ A3E4D35926E0FD2900C9F175 /* PBXTargetDependency */,
);
name = "quick-symlink";
productName = "quick-symlink";
@@ -266,6 +322,23 @@
productReference = A30B9ABE265CA68900ACAA63 /* quick-symlink-extension.appex */;
productType = "com.apple.product-type.app-extension";
};
+ A3E4D35126E0FD2900C9F175 /* hard-link-action-extension */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = A3E4D35B26E0FD2900C9F175 /* Build configuration list for PBXNativeTarget "hard-link-action-extension" */;
+ buildPhases = (
+ A3E4D34E26E0FD2900C9F175 /* Sources */,
+ A3E4D34F26E0FD2900C9F175 /* Frameworks */,
+ A3E4D35026E0FD2900C9F175 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "hard-link-action-extension";
+ productName = "hard-link-action-extension";
+ productReference = A3E4D35226E0FD2900C9F175 /* hard-link-action-extension.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -294,6 +367,10 @@
};
};
};
+ A3E4D35126E0FD2900C9F175 = {
+ CreatedOnToolsVersion = 9.2;
+ ProvisioningStyle = Automatic;
+ };
};
};
buildConfigurationList = A30B9AA2265CA63300ACAA63 /* Build configuration list for PBXProject "quick-symlink" */;
@@ -314,6 +391,7 @@
A30B9AA6265CA63300ACAA63 /* quick-symlink */,
A30B9ABD265CA68900ACAA63 /* quick-symlink-extension */,
A307B42326D255FB002EEF58 /* quick-symlink-tests */,
+ A3E4D35126E0FD2900C9F175 /* hard-link-action-extension */,
);
};
/* End PBXProject section */
@@ -344,6 +422,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ A3E4D35026E0FD2900C9F175 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A31904A426E104FA00D7F69D /* Assets.xcassets in Resources */,
+ A3E4D36626E101B000C9F175 /* Localizable.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -370,6 +457,7 @@
A345C9BF26A0B200004FBF0F /* QuickSymlinkAction.swift in Sources */,
A30B9AAB265CA63300ACAA63 /* AppDelegate.swift in Sources */,
A345C9C526A0B49C004FBF0F /* PasteLinkAction.swift in Sources */,
+ A36F9B0626DFAC27009E95CE /* FileLinkManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -385,6 +473,23 @@
A316477826B7B403001DD969 /* CreateLinkAction.swift in Sources */,
A30D4A4D26A0C18B00BA775B /* QuickSymlinkAction.swift in Sources */,
A30D4A4A26A0C14400BA775B /* CopyPathAction.swift in Sources */,
+ A36F9B0726DFB127009E95CE /* FileLinkManager.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ A3E4D34E26E0FD2900C9F175 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A3E4D36226E0FEF200C9F175 /* ReplaceWithLinkAction.swift in Sources */,
+ A3E4D36326E0FEF400C9F175 /* CreateLinkAction.swift in Sources */,
+ A3E4D36426E0FF8100C9F175 /* ResourcePath.swift in Sources */,
+ A3E4D35526E0FD2900C9F175 /* FinderSync.swift in Sources */,
+ A3E4D36026E0FEED00C9F175 /* CopyPathAction.swift in Sources */,
+ A3E4D35F26E0FEEA00C9F175 /* QuickSymlinkAction.swift in Sources */,
+ A3E4D36126E0FEEF00C9F175 /* PasteLinkAction.swift in Sources */,
+ A3E4D36526E0FF8600C9F175 /* Path.swift in Sources */,
+ A3E4D35E26E0FEE700C9F175 /* FileLinkManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -401,6 +506,11 @@
target = A30B9ABD265CA68900ACAA63 /* quick-symlink-extension */;
targetProxy = A30B9AC4265CA68900ACAA63 /* PBXContainerItemProxy */;
};
+ A3E4D35926E0FD2900C9F175 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = A3E4D35126E0FD2900C9F175 /* hard-link-action-extension */;
+ targetProxy = A3E4D35826E0FD2900C9F175 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -438,7 +548,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "quick-symlink-tests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
@@ -454,7 +564,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "quick-symlink-tests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
@@ -511,7 +621,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@@ -563,7 +673,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -580,7 +690,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "quick-symlink/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
@@ -597,7 +707,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "quick-symlink/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
@@ -612,7 +722,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "quick-symlink-extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink.quick-symlink-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -628,7 +738,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "quick-symlink-extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink.quick-symlink-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -636,6 +746,38 @@
};
name = Release;
};
+ A3E4D35C26E0FD2900C9F175 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "hard-link-action-extension/hard-link-action-extension.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ INFOPLIST_FILE = "hard-link-action-extension/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink.hard-link-action-extension";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 4.0;
+ };
+ name = Debug;
+ };
+ A3E4D35D26E0FD2900C9F175 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "hard-link-action-extension/hard-link-action-extension.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ INFOPLIST_FILE = "hard-link-action-extension/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ololx.quick-symlink.hard-link-action-extension";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 4.0;
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -675,6 +817,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ A3E4D35B26E0FD2900C9F175 /* Build configuration list for PBXNativeTarget "hard-link-action-extension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ A3E4D35C26E0FD2900C9F175 /* Debug */,
+ A3E4D35D26E0FD2900C9F175 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = A30B9A9F265CA63300ACAA63 /* Project object */;