Skip to content

Commit

Permalink
Merge branch 'release/0.2.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
msudgh committed Aug 4, 2024
2 parents 4950966 + 9000de1 commit 7c1f7e2
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 41 deletions.
10 changes: 2 additions & 8 deletions .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@
"extends": "@istanbuljs/nyc-config-typescript",
"all": true,
"check-coverage": false,
"extensions": [
".ts"
],
"reporter": [
"text",
"html",
"lcov"
],
"extensions": [".ts"],
"reporter": ["text", "html", "lcov"],
"exclude": [
"eslint.config.cjs",
"coverage/**",
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ovm (Obsidian Vaults Manager) is a CLI application designed to streamline the ma
- [Usage](#usage)
- [Commands](#commands)
- [`ovm config init`](#ovm-config-init)
- [`ovm config edit`](#ovm-config-edit)
- [`ovm plugins install`](#ovm-plugins-install)
- [`ovm plugins prune`](#ovm-plugins-prune)
- [`ovm plugins uninstall`](#ovm-plugins-uninstall)
Expand All @@ -33,10 +34,17 @@ USAGE

### `ovm config init`

Configure an ovm.json config file in user's home dir.
Configure ovm config file.

- _Usage:_ `ovm help config init`
- _See code:_ [src/commands/config/init.ts](src/commands/config/init.ts)
-
### `ovm config edit`

Edit ovm config file.

- _Usage:_ `ovm help config edit`
- _See code:_ [src/commands/config/edit.ts](src/commands/config/edit.ts)

### `ovm plugins install`

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "ovm",
"description": "Obsidian Vaults Manager",
"type": "commonjs",
"version": "0.2.3",
"version": "0.2.4",
"license": "MIT",
"author": "Masoud Ghorbani",
"homepage": "https://github.com/msudgh/ovm",
Expand Down Expand Up @@ -46,6 +46,9 @@
],
"topicSeparator": " ",
"topics": {
"config": {
"description": "Init and edit ovm config file"
},
"plugins": {
"description": "Manage plugins of the vaults"
},
Expand Down
100 changes: 100 additions & 0 deletions src/commands/config/edit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { flush } from '@oclif/core'
import { ArgInput } from '@oclif/core/lib/parser'
import { exec } from 'child_process'
import FactoryCommand, {
CommonFlags,
FactoryFlags,
} from '../../providers/command'
import { safeLoadConfig } from '../../providers/config'
import { logger } from '../../utils/logger'

const getDefaultEditorCommandByOS = (filePath: string): string => {
switch (process.platform) {
case 'win32':
return `notepad ${filePath}`
case 'darwin':
return `open -e ${filePath}`
case 'linux':
return `xdg-open ${filePath}`
default:
throw new Error('Unsupported OS')
}
}

const openTextEditor = (filePath: string): Promise<boolean | Error> => {
const command = getDefaultEditorCommandByOS(filePath)
const childLogger = logger.child({ filePath, command })

childLogger.debug('Editing config file')

return new Promise((resolve, reject) => {
const editorProcess = exec(command, (error, stdout, stderr) => {
if (error) {
childLogger.error(`Error opening editor`, { error })
reject(error)
}
})

editorProcess.on('close', (code) => {
if (code !== 0) {
reject(new Error(`Command failed with code ${code}`))
}
resolve(true)
})
})
}

/**
* Edit ovm config file.
*/
export default class Edit extends FactoryCommand {
static readonly aliases = ['ce', 'config:edit']
static override readonly description = `Edit ovm config file.`
static override readonly examples = ['<%= config.bin %> <%= command.id %>']
static override readonly flags = {
...this.commonFlags,
}

/**
* Executes the command.
* Parses the arguments and flags, and calls the action method.
* Handles errors and ensures flushing of logs.
*/
public async run() {
try {
const { args, flags } = await this.parse(Edit)
await this.action(args, this.flagsInterceptor(flags))
} catch (error) {
this.handleError(error)
} finally {
flush()
}
}

/**
* Main action method for the command.
* @param {ArgInput} args - The arguments passed to the command.
* @param {FactoryFlags<InitFlags>} flags - The flags passed to the command.
* @returns {Promise<void>}
*/
private async action(
args: ArgInput,
flags: FactoryFlags<CommonFlags>,
): Promise<void> {
const { data: config, error } = await safeLoadConfig(flags.config)

if (config) {
const isOpen = await openTextEditor(flags.config)

if (isOpen) {
this.log(
`Config file opened in text editor and enjoy editing!\nAfter you are done, save and close the editor to continue with a new command.`,
)
}
}

if (error) {
throw error
}
}
}
4 changes: 2 additions & 2 deletions src/commands/config/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { logger } from '../../utils/logger'
*/
export default class Init extends FactoryCommand {
static readonly aliases = ['ci', 'config:init']
static override readonly description = `Configure an ovm.json config file in user's home dir.`
static override readonly description = `Configure ovm config file.`
static override readonly examples = ['<%= config.bin %> <%= command.id %>']
static override readonly flags = {
...this.commonFlags,
Expand Down Expand Up @@ -45,7 +45,7 @@ export default class Init extends FactoryCommand {
flags: FactoryFlags<CommonFlags>,
): Promise<void> {
try {
const { data: config, error } = await safeLoadConfig()
const { data: config, error } = await safeLoadConfig(flags.config)

if (config) {
logger.error('File already exists!', { config: flags.config })
Expand Down
34 changes: 23 additions & 11 deletions src/commands/plugins/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Vault,
} from 'obsidian-utils'
import FactoryCommand, { FactoryFlags } from '../../providers/command'
import { Config, Plugin, safeLoadConfig, writeConfig } from '../../providers/config'
import { Config, safeLoadConfig, writeConfig } from '../../providers/config'
import {
findPluginInRegistry,
handleExceedRateLimitError,
Expand Down Expand Up @@ -95,7 +95,7 @@ export default class Install extends FactoryCommand {
success: loadConfigSuccess,
data: config,
error: loadConfigError,
} = await safeLoadConfig()
} = await safeLoadConfig(flags.config)

if (!loadConfigSuccess) {
logger.error('Failed to load config', { error: loadConfigError })
Expand All @@ -108,15 +108,15 @@ export default class Install extends FactoryCommand {
// Check if pluginId is provided and install only that plugin
const { pluginId } = args
if (pluginId) {
await this.installPluginInVaults(selectedVaults, pluginId, enable)
await this.installPluginInVaults(selectedVaults, config, pluginId, enable)
} else {
await this.installPluginsInVaults(selectedVaults, config.plugins, enable)
await this.installPluginsInVaults(selectedVaults, config, enable)
}
}

private async installPluginsInVaults(
vaults: Vault[],
plugins: Plugin[],
config: Config,
enable: boolean,
specific = false,
) {
Expand All @@ -125,7 +125,7 @@ export default class Install extends FactoryCommand {
const installedPlugins = []
const failedPlugins = []

for (const stagePlugin of plugins) {
for (const stagePlugin of config.plugins) {
const childLogger = logger.child({ stagePlugin, vault })

const pluginInRegistry = await findPluginInRegistry(stagePlugin.id)
Expand All @@ -138,7 +138,7 @@ export default class Install extends FactoryCommand {
continue
}

stagePlugin.version = stagePlugin.version ?? 'latest';
stagePlugin.version = stagePlugin.version ?? 'latest'

try {
await installPluginFromGithub(
Expand All @@ -158,8 +158,10 @@ export default class Install extends FactoryCommand {

if (specific) {
// Add the plugin to the config
const newPlugins = new Set([...plugins])
await writeConfig({ plugins: [...newPlugins] })
await writeConfig({
...config,
plugins: [...new Set([...config.plugins])],
})
}

childLogger.debug(`Installed plugin`)
Expand Down Expand Up @@ -190,12 +192,22 @@ export default class Install extends FactoryCommand {
})
}

private async installPluginInVaults(vaults: Vault[], id: string, enable: boolean) {
private async installPluginInVaults(
vaults: Vault[],
config: Config,
id: string,
enable: boolean,
) {
const pluginInRegistry = await findPluginInRegistry(id)
if (!pluginInRegistry) {
throw new PluginNotFoundInRegistryError(id)
}

await this.installPluginsInVaults(vaults, [{ id }], enable, true)
await this.installPluginsInVaults(
vaults,
{ ...config, plugins: [{ id }] },
enable,
true,
)
}
}
2 changes: 1 addition & 1 deletion src/commands/plugins/prune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default class Prune extends FactoryCommand {
success: loadConfigSuccess,
data: config,
error: loadConfigError,
} = await safeLoadConfig()
} = await safeLoadConfig(flags.config)

if (!loadConfigSuccess) {
logger.error('Failed to load config', { error: loadConfigError })
Expand Down
2 changes: 1 addition & 1 deletion src/commands/plugins/uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default class Uninstall extends FactoryCommand {
success: loadConfigSuccess,
data: config,
error: loadConfigError,
} = await safeLoadConfig()
} = await safeLoadConfig(flags.config)

if (!loadConfigSuccess) {
logger.error('Failed to load config', { error: loadConfigError })
Expand Down
2 changes: 1 addition & 1 deletion src/commands/reports/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default class Stats extends FactoryCommand {
success: loadConfigSuccess,
data: config,
error: loadConfigError,
} = await safeLoadConfig()
} = await safeLoadConfig(flags.config)
if (!loadConfigSuccess) {
logger.error('Failed to load config', { error: loadConfigError })
process.exit(1)
Expand Down
1 change: 0 additions & 1 deletion src/providers/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ export default class FactoryCommand extends Command {
if (error instanceof ExitPromptError) {
logger.debug('Exit prompt error:', { error })
} else if (error instanceof Error) {
logger.debug('An error occurred while installation:', { error })
handle(error)
}
}
Expand Down
15 changes: 8 additions & 7 deletions src/providers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ const PluginSchema = z.object({
export type Plugin = z.infer<typeof PluginSchema>

interface Hotkey {
modifiers: string[];
key: string;
modifiers: string[]
key: string
}

interface HotkeysConfig {
[command: string]: Hotkey[];
[command: string]: Hotkey[]
}

export const ConfigSchema = z.object({
Expand Down Expand Up @@ -46,7 +46,7 @@ type SafeLoadConfigResult =
| SafeLoadConfigResultError

export const safeLoadConfig = (
configPath = DEFAULT_CONFIG_PATH,
configPath: string,
): Promise<SafeLoadConfigResult> => {
return new Promise((resolve) => {
try {
Expand All @@ -55,8 +55,9 @@ export const safeLoadConfig = (
const { success, data, error } = ConfigSchema.safeParse(parsed)

if (!success) {
logger.debug('Invalid config file', { data, error })
throw new Error('Invalid config file')
throw new Error(
`Invalid config file\nIssues: ${JSON.stringify(error.issues)}`,
)
}

resolve({ success, data, error: undefined })
Expand Down Expand Up @@ -87,7 +88,7 @@ export const writeConfig = (
try {
const content = JSON.stringify(config, null, 2)
writeFileSync(configPath, content)
logger.debug('Config written', { configPath })
logger.debug('Config written', { configPath })
resolve()
} catch (error) {
reject(error as Error)
Expand Down
9 changes: 2 additions & 7 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,11 @@
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"types": [
"node",
"mocha"
],
"types": ["node", "mocha"],
"noImplicitAny": true,
"skipLibCheck": false,
"sourceMap": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"src/**/*"
]
"include": ["src/**/*"]
}

0 comments on commit 7c1f7e2

Please sign in to comment.