Skip to content

Commit

Permalink
Merge pull request #4 from ololx/develop
Browse files Browse the repository at this point in the history
Add the relative path usage instead absolute path in symlink target URL
  • Loading branch information
ololx authored Aug 22, 2021
2 parents 3a82460 + cd54055 commit 949387f
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 11 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

- Refactor application.

## [0.7.0] - 2021-08-22

### Added

- Added new classes `Path` for working with path's and creating relative path from specified directory.
- Add unit-tests cases for the `Path` class.

### Changed

- Change soft link creation using relative instead absolute path.

## [0.6.0] - 2021-08-02

### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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_07,_2021-informational?style=flat-square)](BADGES_GUIDE.md#release-date) [![last commit](https://img.shields.io/badge/last_commit-August_20,_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.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)

[![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)

Expand Down
5 changes: 3 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
- [x] Develop the `Finder extension` which allows to create a symlinks for selected folders and files via contextual menu.
- [x] Add the new menu item for replacing selected folders and files with symlinks.
- [x] Add the new menu item for creating symlink in a parent directory (parent for target objects).
- [ ] Optional feature - use relative path instead absolute path in symlink target URL (if target and link located in one volume)
- [ ] Develop additional `Finder extension` which allows to create a `hard links` for selected folders and files via contextual menu.
- [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
- [ ] 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
Expand Down
20 changes: 20 additions & 0 deletions commons/FileSystem/Path.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Path.swift
// quick-symlink
//
// Created by Alexander A. Kropotin on 22/08/2021.
// Copyright © 2021 Alexander A. Kropotin. All rights reserved.
//

import Foundation

public protocol Path {

func relativize(to other: Path!) -> Path!;

func getPathFragments() -> [String]!;

func toUrl() -> URL?;

func toUriString() -> String?;
}
82 changes: 82 additions & 0 deletions commons/FileSystem/ResourcePath.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// ResourcePath.swift
// quick-symlink
//
// Created by Alexander A. Kropotin on 22/08/2021.
// Copyright © 2021 Alexander A. Kropotin. All rights reserved.
//

import Foundation

public class ResourcePath: Path {

public static func of(url: URL!) -> Path! {
return ResourcePath.of(fragments: url.pathComponents)
}

public static func of(fragments: [String]!) -> Path! {
return ResourcePath.init(of: fragments);
}

private var uriFragments: [String]!;

public init(of fragments: [String]) {
self.uriFragments = fragments;
}

public func getPathFragments() -> [String]! {
return self.uriFragments;
}

public func relativize(to other: Path!) -> Path! {
var pathFragments = self.uriFragments;
var targetPathFragments = other.getPathFragments();

var destinationPath = URL.init(string: "./")!;
for targetPathFragment in targetPathFragments! {
if (!(pathFragments?.contains(targetPathFragment))!) {
break;
}

pathFragments?.remove(at: 0);
targetPathFragments?.remove(at: 0);
}

for _ in targetPathFragments! {
destinationPath.appendPathComponent("../");
}

for pathFragment in pathFragments! {
destinationPath.appendPathComponent(pathFragment);
}

//pathFragments!.append(contentsOf: targetPathFragments!);

return ResourcePath.of(url: destinationPath);
}

public func toUrl() -> URL? {
if self.uriFragments.count == 0 {
return nil;
}

var uri = URL.init(string: self.uriFragments.first!)!;
for fragment in self.uriFragments.dropFirst().dropLast() {
uri.appendPathComponent(fragment);
uri.appendPathComponent("/");
}
uri.appendPathComponent(self.uriFragments.last!);

return uri;
}

public func toUriString() -> String? {
if self.uriFragments.count == 0 {
return nil;
}

return self.toUrl()!.absoluteString;
}


}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class CreateLinkAction: QuickSymlinkAction {
let targetPath = self.getTargetPath(path, to: path.deletingLastPathComponent());

do {
try FileManager.default.createSymbolicLink(at: targetPath!, withDestinationURL: path);
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class PasteLinkAction: QuickSymlinkAction {
let targetPath = self.getTargetPath(pathUrl, to: target);

do {
try FileManager.default.createSymbolicLink(at: targetPath!, withDestinationURL: URL(fileURLWithPath: path));
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);
}
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class ReplaceWithLinkAction: QuickSymlinkAction {

do {
try FileManager.default.moveItem(at: pathUrl, to: targetPath!);
try FileManager.default.createSymbolicLink(at: pathUrl, withDestinationURL: 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);
}
Expand Down
22 changes: 22 additions & 0 deletions quick-symlink-tests/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
49 changes: 49 additions & 0 deletions quick-symlink-tests/ResourcePathTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// ResourcePathTest.swift
// quick-symlink-tests
//
// Created by Alexander A. Kropotin on 22/08/2021.
// Copyright © 2021 Alexander A. Kropotin. All rights reserved.
//

import XCTest

class ResourcePathTest: XCTestCase {

func test_toURL_methodExecution_returnedURLIsEqualToInitialURL() {
let uri: URL = URL.init(string: "/a/b/c/d")!;
let path: Path = ResourcePath.of(url: uri);

XCTAssert(path.toUrl() == uri, "The Path URL is not equal to URL");
}

func test_relativize_whenCurrentDirectoryIsNestedToOtherDirectory_thenReturnPathStartingFromOtherDirectory() {
let currentUri: URL = URL.init(string: "/a/b/c/d")!;
let otherUri: URL = URL.init(string: "/a/b")!;

let relativePath: Path = ResourcePath.of(url: currentUri)
.relativize(to: ResourcePath.of(url: otherUri));

XCTAssert(relativePath.toUriString() == "./c/d", "The relative path is wrong");
}

func test_relativize_whenOtherDirectoryIsNestedToCurrentDirectory_thenReturnPathWithOnlyJumpsAboveOtherDirectory() {
let currentUri: URL = URL.init(string: "/a/b")!;
let otherUri: URL = URL.init(string: "/a/b/c/d")!;

let relativePath: Path = ResourcePath.of(url: currentUri)
.relativize(to: ResourcePath.of(url: otherUri));

XCTAssert(relativePath.toUriString() == "./../..", "The relative path is wrong");
}

func test_relativize_whenCurrentDirectoryAndOtherDirectoryAreNestedToGeneralDirectoryy_thenReturnPathWithJumpsAboveOtherDirectoryAndPartOfCurrentDirectory() {
let currentUri: URL = URL.init(string: "/a/b/c1/d1")!;
let otherUri: URL = URL.init(string: "/a/b/c2/d2")!;

let relativePath: Path = ResourcePath.of(url: currentUri)
.relativize(to: ResourcePath.of(url: otherUri));

XCTAssert(relativePath.toUriString() == "./../../c1/d1", "The relative path is wrong");
}
}
Loading

0 comments on commit 949387f

Please sign in to comment.