Skip to content

Commit

Permalink
Fix uninstalling plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
ziulev committed May 6, 2022
1 parent bec4a79 commit a816f99
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 559 deletions.
4 changes: 2 additions & 2 deletions macos/spotter-macOS/Shell/Shell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class Shell: RCTEventEmitter {
resolver resolve: RCTPromiseResolveBlock,
rejecter reject: RCTPromiseRejectBlock) -> Void {
do {
let output = try shellOut(to: command, at: "/")
resolve(output)
let output = try shellOut(to: command)
resolve(output);
} catch {
let error = error as! ShellOutError
print(error.message)
Expand Down
222 changes: 0 additions & 222 deletions macos/spotter-macOS/Shell/ShellOut.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,228 +117,6 @@ public struct ShellOutCommand {
}
}

/// Git commands
public extension ShellOutCommand {
/// Initialize a git repository
static func gitInit() -> ShellOutCommand {
return ShellOutCommand(string: "git init")
}

/// Clone a git repository at a given URL
static func gitClone(url: URL, to path: String? = nil, allowingPrompt: Bool = true) -> ShellOutCommand {
var command = "\(git(allowingPrompt: allowingPrompt)) clone \(url.absoluteString)"
path.map { command.append(argument: $0) }
command.append(" --quiet")

return ShellOutCommand(string: command)
}

/// Create a git commit with a given message (also adds all untracked file to the index)
static func gitCommit(message: String, allowingPrompt: Bool = true) -> ShellOutCommand {
var command = "\(git(allowingPrompt: allowingPrompt)) add . && git commit -a -m"
command.append(argument: message)
command.append(" --quiet")

return ShellOutCommand(string: command)
}

/// Perform a git push
static func gitPush(remote: String? = nil, branch: String? = nil, allowingPrompt: Bool = true) -> ShellOutCommand {
var command = "\(git(allowingPrompt: allowingPrompt)) push"
remote.map { command.append(argument: $0) }
branch.map { command.append(argument: $0) }
command.append(" --quiet")

return ShellOutCommand(string: command)
}

/// Perform a git pull
static func gitPull(remote: String? = nil, branch: String? = nil, allowingPrompt: Bool = true) -> ShellOutCommand {
var command = "\(git(allowingPrompt: allowingPrompt)) pull"
remote.map { command.append(argument: $0) }
branch.map { command.append(argument: $0) }
command.append(" --quiet")

return ShellOutCommand(string: command)
}

/// Run a git submodule update
static func gitSubmoduleUpdate(initializeIfNeeded: Bool = true, recursive: Bool = true, allowingPrompt: Bool = true) -> ShellOutCommand {
var command = "\(git(allowingPrompt: allowingPrompt)) submodule update"

if initializeIfNeeded {
command.append(" --init")
}

if recursive {
command.append(" --recursive")
}

command.append(" --quiet")
return ShellOutCommand(string: command)
}

/// Checkout a given git branch
static func gitCheckout(branch: String) -> ShellOutCommand {
let command = "git checkout".appending(argument: branch)
.appending(" --quiet")

return ShellOutCommand(string: command)
}

private static func git(allowingPrompt: Bool) -> String {
return allowingPrompt ? "git" : "env GIT_TERMINAL_PROMPT=0 git"
}
}

/// File system commands
public extension ShellOutCommand {
/// Create a folder with a given name
static func createFolder(named name: String) -> ShellOutCommand {
let command = "mkdir".appending(argument: name)
return ShellOutCommand(string: command)
}

/// Create a file with a given name and contents (will overwrite any existing file with the same name)
static func createFile(named name: String, contents: String) -> ShellOutCommand {
var command = "echo"
command.append(argument: contents)
command.append(" > ")
command.append(argument: name)

return ShellOutCommand(string: command)
}

/// Move a file from one path to another
static func moveFile(from originPath: String, to targetPath: String) -> ShellOutCommand {
let command = "mv".appending(argument: originPath)
.appending(argument: targetPath)

return ShellOutCommand(string: command)
}

/// Copy a file from one path to another
static func copyFile(from originPath: String, to targetPath: String) -> ShellOutCommand {
let command = "cp".appending(argument: originPath)
.appending(argument: targetPath)

return ShellOutCommand(string: command)
}

/// Remove a file
static func removeFile(from path: String, arguments: [String] = ["-f"]) -> ShellOutCommand {
let command = "rm".appending(arguments: arguments)
.appending(argument: path)

return ShellOutCommand(string: command)
}

/// Open a file using its designated application
static func openFile(at path: String) -> ShellOutCommand {
let command = "open".appending(argument: path)
return ShellOutCommand(string: command)
}

/// Read a file as a string
static func readFile(at path: String) -> ShellOutCommand {
let command = "cat".appending(argument: path)
return ShellOutCommand(string: command)
}

/// Create a symlink at a given path, to a given target
static func createSymlink(to targetPath: String, at linkPath: String) -> ShellOutCommand {
let command = "ln -s".appending(argument: targetPath)
.appending(argument: linkPath)

return ShellOutCommand(string: command)
}

/// Expand a symlink at a given path, returning its target path
static func expandSymlink(at path: String) -> ShellOutCommand {
let command = "readlink".appending(argument: path)
return ShellOutCommand(string: command)
}
}

/// Marathon commands
public extension ShellOutCommand {
/// Run a Marathon Swift script
static func runMarathonScript(at path: String, arguments: [String] = []) -> ShellOutCommand {
let command = "marathon run".appending(argument: path)
.appending(arguments: arguments)

return ShellOutCommand(string: command)
}

/// Update all Swift packages managed by Marathon
static func updateMarathonPackages() -> ShellOutCommand {
return ShellOutCommand(string: "marathon update")
}
}

/// Swift Package Manager commands
public extension ShellOutCommand {
/// Enum defining available package types when using the Swift Package Manager
enum SwiftPackageType: String {
case library
case executable
}

/// Enum defining available build configurations when using the Swift Package Manager
enum SwiftBuildConfiguration: String {
case debug
case release
}

/// Create a Swift package with a given type (see SwiftPackageType for options)
static func createSwiftPackage(withType type: SwiftPackageType = .library) -> ShellOutCommand {
let command = "swift package init --type \(type.rawValue)"
return ShellOutCommand(string: command)
}

/// Update all Swift package dependencies
static func updateSwiftPackages() -> ShellOutCommand {
return ShellOutCommand(string: "swift package update")
}

/// Generate an Xcode project for a Swift package
static func generateSwiftPackageXcodeProject() -> ShellOutCommand {
return ShellOutCommand(string: "swift package generate-xcodeproj")
}

/// Build a Swift package using a given configuration (see SwiftBuildConfiguration for options)
static func buildSwiftPackage(withConfiguration configuration: SwiftBuildConfiguration = .debug) -> ShellOutCommand {
return ShellOutCommand(string: "swift build -c \(configuration.rawValue)")
}

/// Test a Swift package using a given configuration (see SwiftBuildConfiguration for options)
static func testSwiftPackage(withConfiguration configuration: SwiftBuildConfiguration = .debug) -> ShellOutCommand {
return ShellOutCommand(string: "swift test -c \(configuration.rawValue)")
}
}

/// Fastlane commands
public extension ShellOutCommand {
/// Run Fastlane using a given lane
static func runFastlane(usingLane lane: String) -> ShellOutCommand {
let command = "fastlane".appending(argument: lane)
return ShellOutCommand(string: command)
}
}

/// CocoaPods commands
public extension ShellOutCommand {
/// Update all CocoaPods dependencies
static func updateCocoaPods() -> ShellOutCommand {
return ShellOutCommand(string: "pod update")
}

/// Install all CocoaPods dependencies
static func installCocoaPods() -> ShellOutCommand {
return ShellOutCommand(string: "pod install")
}
}

/// Error type thrown by the `shellOut()` function, in case the given command failed
public struct ShellOutError: Swift.Error {
/// The termination status of the command that was run
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@babel/core": "7.17.10",
"@babel/runtime": "7.17.9",
"@react-native-community/eslint-config": "3.0.1",
"@spotter-app/core": "^2.0.0-beta.63",
"@spotter-app/core": "^2.0.0-beta.64",
"@types/jest": "27.5.0",
"@types/react": "18.0.8",
"@types/react-native": "0.67.6",
Expand Down
2 changes: 0 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ export const SPOTTER_HOTKEY_IDENTIFIER = 'spotter';

export const SHOW_OPTIONS_DELAY = 500;

export const PATH = 'export PATH="/usr/local/share/npm/bin:/usr/local/bin:/usr/local/sbin:~/bin:$PATH"';

export const LIGHT_THEME = '#efefef,#101010,#dddddd,#000000,#0f60cf,#fefefe';
export const DARK_THEME = '#212121,#ffffff,#3c3c3c,#ffffff,#0f60cf,#fefefe';

Expand Down
3 changes: 2 additions & 1 deletion src/native/api/shell.api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { NativeModules } from 'react-native';
import { PATH } from '../../constants';
import { SpotterShellApi } from '../../interfaces';

const PATH = 'export PATH="/usr/local/share/npm/bin:/usr/local/bin:/usr/local/sbin:~/bin:$PATH"';

export class ShellApi implements SpotterShellApi {
private shell = NativeModules.Shell;

Expand Down
19 changes: 14 additions & 5 deletions src/plugins/plugins-manager.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import { onQueryFilter, OnQueryOption, Plugin, randomPort, SpotterPluginApi } from '@spotter-app/core';
import {
onQueryFilter,
OnQueryOption,
Plugin,
SpotterPluginApi,
} from '@spotter-app/core';
import { ShellApi } from '../native';
import FS from 'react-native-fs';
import { INTERNAL_PLUGINS } from '../constants';

const externalPluginsRepos = [
'spotter-application/applications-plugin',
'spotter-application/emoji-plugin',
];

export const randomPort = (): number =>
(Math.floor(10000 + Math.random() * 9000));

interface ExternalPluginVersion {
name: string,
versionName: string,
Expand All @@ -26,10 +39,6 @@ export class PluginsManagerPlugin extends SpotterPluginApi {
private async pluginsMenu(query: string): Promise<OnQueryOption[]> {
const plugins = await this.spotter.plugins.get();

const externalPluginsRepos = [
'spotter-application/applications-plugin',
];

const externalPlugins: ExternalPluginVersion[] = await externalPluginsRepos.reduce(
async (asyncAcc, repo) => {
const { name, published_at, assets } = await fetch(`https://api.github.com/repos/${repo}/releases/latest`).then(r => r?.json()).catch(() => {});
Expand Down
15 changes: 9 additions & 6 deletions src/providers/events.provider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { SpotterCommandType, SpotterCommand } from '@spotter-app/core';
import React, { FC, useEffect } from 'react';
import React, { FC, PropsWithChildren, useEffect } from 'react';
import { PLUGINS_TO_INSTALL, SPOTTER_HOTKEY_IDENTIFIER } from '../constants';
import { isPluginOnQueryOption, PluginRegistryOption, SpotterHotkeyEvent } from '../interfaces';
import { useApi } from './api.provider';
import { useSettings } from './settings.provider';
import { replaceOptions, getHistoryPath, sortOptions, shouldUpgrade } from '../helpers';
import { replaceOptions, getHistoryPath, sortOptions } from '../helpers';
import { useHistory } from './history.provider';
import { useSpotterState } from './state.provider';
import { usePlugins } from './plugins.provider';
Expand Down Expand Up @@ -44,7 +44,7 @@ type NextSpotterVersion = {

export const EventsContext = React.createContext<Context>(context);

export const EventsProvider: FC<{}> = (props) => {
export const EventsProvider: FC<{}> = (props: PropsWithChildren<{}>) => {
const { panel, shell, hotkey, notifications, storage } = useApi();
const { getSettings, patchSettings } = useSettings();
const { getHistory, increaseHistory } = useHistory();
Expand Down Expand Up @@ -144,6 +144,9 @@ export const EventsProvider: FC<{}> = (props) => {
now: number,
lastRequestedAt: number
): Promise<NextSpotterVersion> => {
return null;


if ((now - lastRequestedAt) < FIVE_MIN) {
return null;
}
Expand All @@ -152,9 +155,9 @@ export const EventsProvider: FC<{}> = (props) => {
'https://api.github.com/repos/ziulev/spotter/releases/latest'
).then(r => r.json());

if (!shouldUpgrade(packageJson.version, latestVersion.name)) {
return null;
}
// if (!shouldUpgrade(packageJson.version, latestVersion.name)) {
// return null;
// }

const bundle = latestVersion.assets.find((a: {name: string}) => a.name === 'spotter.dmg');
return {
Expand Down
7 changes: 3 additions & 4 deletions src/providers/plugins.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ export const PluginsProvider: FC<{}> = (props: PropsWithChildren<{}>) => {

const getPlugins: () => Promise<Plugin[]> = async () => {
const plugins = await storage.getItem<Plugin[]>(PLUGINS_STORAGE_KEY);
console.log(plugins?.map(p => ({...p, connected: !!activePlugins$.value.find(ap => ap.port == p.port)})))
return plugins?.map(p => ({...p, connected: !!activePlugins$.value.find(ap => ap.port == p.port)})) ?? [];
}

Expand All @@ -141,7 +140,6 @@ export const PluginsProvider: FC<{}> = (props: PropsWithChildren<{}>) => {
const plugins = await getPlugins();
storage.setItem(PLUGINS_STORAGE_KEY, plugins.filter(p => p.port !== port));
removePluginRegistries(port);
killPort(port);
const activePlugin = activePlugins$.value.find(p =>
p.port=== port,
);
Expand All @@ -150,6 +148,7 @@ export const PluginsProvider: FC<{}> = (props: PropsWithChildren<{}>) => {
p.port !== port,
));
}
killPort(port);
}

const removePluginRegistries = (
Expand Down Expand Up @@ -424,14 +423,14 @@ export const PluginsProvider: FC<{}> = (props: PropsWithChildren<{}>) => {
port: number,
): Promise<string> => {
await killPort(port);
return await shell.execute(`${path} ${port}`);
return await shell.execute(`nohup ${path} ${port} > /dev/null 2>&1 &`);
}


const killPort = async (
port: number,
) => {
return await shell.execute(`lsof -ti:${port} | xargs kill`);
return await shell.execute(`lsof -n -i:${port} | grep LISTEN | awk '{ print $2 }' | xargs kill`);
}

const getPluginChannel = (port: number): ChannelForSpotter | null => {
Expand Down
Loading

0 comments on commit a816f99

Please sign in to comment.