Compare commits

...

3 Commits
0.17 ... 0.18

Author SHA1 Message Date
5c0b67b7fb version bump 2020-05-17 18:14:09 +02:00
1520e10a59 do not allow multiple instances 2020-05-17 18:13:50 +02:00
f9c645120b run in shell to set paths and find restic 2020-05-17 18:12:58 +02:00
5 changed files with 60 additions and 41 deletions

View File

@@ -4,11 +4,11 @@ import minimist from 'minimist'
import { init } from './config' import { init } from './config'
import handlers, { error, help } from './handlers' import handlers, { error, help } from './handlers'
import { Config } from './types' import { Config } from './types'
import { readLock, writeLock, unlock } from './lock'
process.on('uncaughtException', err => { process.on('uncaughtException', err => {
console.log(err.message) console.log(err.message)
unlock()
process.exit(1) process.exit(1)
}) })
@@ -26,7 +26,7 @@ export const { _: commands, ...flags } = minimist(process.argv.slice(2), {
string: ['l', 'b'], string: ['l', 'b'],
}) })
export const VERSION = '0.17' export const VERSION = '0.18'
export const INSTALL_DIR = '/usr/local/bin' export const INSTALL_DIR = '/usr/local/bin'
export const VERBOSE = flags.verbose export const VERBOSE = flags.verbose
@@ -36,6 +36,17 @@ export let config: Config
async function main() { async function main() {
config = init() config = init()
// Don't let 2 instances run on the same config
const lock = readLock()
if (lock.running) {
console.log('An instance of autorestic is already running for this config file'.red)
return
}
writeLock({
...lock,
running: true,
})
// For dev // For dev
// return await handlers['cron']([], { ...flags, all: true }) // return await handlers['cron']([], { ...flags, all: true })
@@ -46,6 +57,7 @@ async function main() {
const fn = handlers[command] || error const fn = handlers[command] || error
await fn(args, flags) await fn(args, flags)
unlock()
} }

View File

@@ -1,49 +1,21 @@
import fs from 'fs'
import CronParser from 'cron-parser' import CronParser from 'cron-parser'
import { config } from './autorestic' import { config } from './autorestic'
import { checkAndConfigureBackendsForLocations } from './backend' import { checkAndConfigureBackendsForLocations } from './backend'
import { Location, Lockfile } from './types' import { Location } from './types'
import { backupLocation } from './backup' import { backupLocation } from './backup'
import { pathRelativeToConfigFile } from './utils' import { readLock, writeLock } from './lock'
const getLockFileName = () => {
const LOCK_FILE = '.autorestic.lock'
return pathRelativeToConfigFile(LOCK_FILE)
}
const readLock = (): Lockfile => {
const name = getLockFileName()
let lock = {}
try {
lock = JSON.parse(fs.readFileSync(name, { encoding: 'utf-8' }))
} catch { }
return lock
}
const writeLock = (diff: Lockfile = {}) => {
const name = getLockFileName()
const newLock = Object.assign(
readLock(),
diff
)
fs.writeFileSync(name, JSON.stringify(newLock, null, 2), { encoding: 'utf-8' })
}
const runCronForLocation = (name: string, location: Location) => { const runCronForLocation = (name: string, location: Location) => {
const lock = readLock()[name] const lock = readLock()
const parsed = CronParser.parseExpression(location.cron || '') const parsed = CronParser.parseExpression(location.cron || '')
const last = parsed.prev() const last = parsed.prev()
if (!lock || last.toDate().getTime() > lock.lastRun) { if (!lock.crons[name] || last.toDate().getTime() > lock.crons[name].lastRun) {
backupLocation(name, location) backupLocation(name, location)
writeLock({ lock.crons[name] = { lastRun: Date.now() }
[name]: { writeLock(lock)
...lock,
lastRun: Date.now()
}
})
} else { } else {
console.log(`${name.yellow} ▶ Skipping. Sheduled for: ${parsed.next().toString().underline.blue}`) console.log(`${name.yellow} ▶ Skipping. Sheduled for: ${parsed.next().toString().underline.blue}`)
} }

32
src/lock.ts Normal file
View File

@@ -0,0 +1,32 @@
import fs from 'fs'
import { pathRelativeToConfigFile } from "./utils"
import { Lockfile } from "./types"
export const getLockFileName = () => {
const LOCK_FILE = '.autorestic.lock'
return pathRelativeToConfigFile(LOCK_FILE)
}
export const readLock = (): Lockfile => {
const name = getLockFileName()
let lock = {
running: false,
crons: {}
}
try {
lock = JSON.parse(fs.readFileSync(name, { encoding: 'utf-8' }))
} catch { }
return lock
}
export const writeLock = (lock: Lockfile) => {
const name = getLockFileName()
fs.writeFileSync(name, JSON.stringify(lock, null, 2), { encoding: 'utf-8' })
}
export const unlock = () => {
writeLock({
...readLock(),
running: false,
})
}

View File

@@ -93,9 +93,12 @@ export type Config = {
} }
export type Lockfile = { export type Lockfile = {
running: boolean
crons: {
[name: string]: { [name: string]: {
lastRun: number lastRun: number
} }
} }
}
export type Flags = { [arg: string]: any } export type Flags = { [arg: string]: any }

View File

@@ -30,7 +30,7 @@ export const execPlain = (command: string, opt: SpawnSyncOptions = {}) => {
const split = command.split(' ') const split = command.split(' ')
if (split.length < 1) throw new Error(`The command ${command} is not valid`.red) if (split.length < 1) throw new Error(`The command ${command} is not valid`.red)
return exec(split[0], split.slice(1), opt) return exec(split[0], split.slice(1), { shell: true, ...opt })
} }
export const checkIfResticIsAvailable = () => export const checkIfResticIsAvailable = () =>
@@ -42,7 +42,7 @@ export const checkIfResticIsAvailable = () =>
) )
export const checkIfCommandIsAvailable = (cmd: string, errorMsg?: string) => { export const checkIfCommandIsAvailable = (cmd: string, errorMsg?: string) => {
if (spawnSync(cmd).error) if (spawnSync(cmd, { shell: true }).error)
throw new Error(errorMsg ? errorMsg : `"${cmd}" is not installed`.red) throw new Error(errorMsg ? errorMsg : `"${cmd}" is not installed`.red)
} }