mirror of
https://github.com/ivuorinen/sysvinit-service-generator.git
synced 2026-01-26 03:24:03 +00:00
Initial commit
This commit is contained in:
15
.eslintrc.cjs
Normal file
15
.eslintrc.cjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @ivuorinen
|
||||
4
.github/renovate.json
vendored
Normal file
4
.github/renovate.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>ivuorinen/.github:renovate-config"]
|
||||
}
|
||||
31
.github/workflows/compress-images.yml
vendored
Normal file
31
.github/workflows/compress-images.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
# Compress images on demand (workflow_dispatch), and at 11pm every Sunday (schedule).
|
||||
# Open a Pull Request if any images can be compressed.
|
||||
name: Compress Images on Demand
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "00 23 * * 0"
|
||||
jobs:
|
||||
CompressOnDemandOrSchedule:
|
||||
name: calibreapp/image-actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Compress Images
|
||||
id: calibre
|
||||
uses: calibreapp/image-actions@main
|
||||
with:
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
compressOnly: true
|
||||
|
||||
- name: Create New Pull Request If Needed
|
||||
if: steps.calibre.outputs.markdown != ''
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
title: Compressed Images Nightly
|
||||
branch-suffix: timestamp
|
||||
commit-message: Compressed Images
|
||||
body: ${{ steps.calibre.outputs.markdown }}
|
||||
26
.github/workflows/dependency-review.yml
vendored
Normal file
26
.github/workflows/dependency-review.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
# Dependency Review Action
|
||||
#
|
||||
# This Action will scan dependency manifest files that change as part of a Pull Request,
|
||||
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
|
||||
# Once installed, if the workflow run is marked as required, PRs introducing
|
||||
# known-vulnerable packages will be blocked from merging.
|
||||
#
|
||||
# Source repository: https://github.com/actions/dependency-review-action
|
||||
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
|
||||
name: "Dependency Review"
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Dependency Review"
|
||||
uses: actions/dependency-review-action@v3
|
||||
30
.github/workflows/pr-compress-images.yml
vendored
Normal file
30
.github/workflows/pr-compress-images.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Compress Images
|
||||
on:
|
||||
pull_request:
|
||||
# Run Image Actions when JPG, JPEG, PNG or WebP files are added or changed.
|
||||
# See https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#onpushpull_requestpaths for reference.
|
||||
paths:
|
||||
- "**.jpg"
|
||||
- "**.jpeg"
|
||||
- "**.png"
|
||||
- "**.webp"
|
||||
jobs:
|
||||
CompressInPR:
|
||||
# Only run on Pull Requests within the same repository, and not from forks.
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
name: calibreapp/image-actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Compress Images
|
||||
uses: calibreapp/image-actions@main
|
||||
with:
|
||||
# The `GITHUB_TOKEN` is automatically generated by GitHub and scoped only to the repository that is
|
||||
# currently running the action. By default, the action can’t update Pull Requests initiated from
|
||||
# forked repositories.
|
||||
# See https://docs.github.com/en/actions/reference/authentication-in-a-workflow and
|
||||
# https://help.github.com/en/articles/virtual-environments-for-github-actions#token-permissions
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
68
.github/workflows/pr-lint.yml
vendored
Normal file
68
.github/workflows/pr-lint.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
#################################
|
||||
#################################
|
||||
## Super Linter GitHub Actions ##
|
||||
#################################
|
||||
#################################
|
||||
name: Lint Code Base
|
||||
|
||||
#
|
||||
# Documentation:
|
||||
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
|
||||
#
|
||||
|
||||
env:
|
||||
MAIN_BRANCH: main
|
||||
|
||||
#############################
|
||||
# Start the job on all push #
|
||||
#############################
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [master, main]
|
||||
# Remove the line above to run when pushing to master
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
|
||||
###############
|
||||
# Set the Job #
|
||||
###############
|
||||
jobs:
|
||||
build:
|
||||
# Name the Job
|
||||
name: Lint Code Base
|
||||
# Set the agent to run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
############################################
|
||||
# Grant status permission for MULTI_STATUS #
|
||||
############################################
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
statuses: write
|
||||
|
||||
##################
|
||||
# Load all steps #
|
||||
##################
|
||||
steps:
|
||||
##########################
|
||||
# Checkout the code base #
|
||||
##########################
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# Full git history is needed to get a proper
|
||||
# list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
|
||||
################################
|
||||
# Run Linter against code base #
|
||||
################################
|
||||
- name: Lint Code Base
|
||||
uses: github/super-linter@v5
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
# Change to 'master' if your main branch differs
|
||||
DEFAULT_BRANCH: ${{ env.MAIN_BRANCH }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
16
.github/workflows/release-drafter.yml
vendored
Normal file
16
.github/workflows/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: Release Drafter
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
update_release_draft:
|
||||
name: ✏️ Draft release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 🚀 Run Release Drafter
|
||||
uses: release-drafter/release-drafter@v5.24.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
47
.github/workflows/stale.yml
vendored
Normal file
47
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
name: Stale
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 8 * * *"
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
permissions:
|
||||
contents: write # only for delete-branch option
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: 🧹 Clean up stale issues and PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 🚀 Run stale
|
||||
uses: actions/stale@v8.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 30
|
||||
days-before-close: 7
|
||||
remove-stale-when-updated: true
|
||||
stale-issue-label: "stale"
|
||||
exempt-issue-labels: "no-stale,help-wanted"
|
||||
stale-issue-message: >
|
||||
There hasn't been any activity on this issue recently, so we
|
||||
clean up some of the older and inactive issues.
|
||||
|
||||
Please make sure to update to the latest version and
|
||||
check if that solves the issue. Let us know if that works for you
|
||||
by leaving a comment 👍
|
||||
|
||||
This issue has now been marked as stale and will be closed if no
|
||||
further activity occurs. Thanks!
|
||||
stale-pr-label: "stale"
|
||||
exempt-pr-labels: "no-stale"
|
||||
stale-pr-message: >
|
||||
There hasn't been any activity on this pull request recently. This
|
||||
pull request has been automatically marked as stale because of that
|
||||
and will be closed if no further activity occurs within 7 days.
|
||||
Thank you for your contributions.
|
||||
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Ismo Vuorinen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
23
README.md
Normal file
23
README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# sysvinit service generator
|
||||
|
||||
This Vue 3 app generates templates for sysvinit services.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Fill in the form with the desired values.
|
||||
2. Copy the generated template.
|
||||
3. Paste it into a new file in `/etc/init.d/`.
|
||||
4. Make the file executable with `chmod +x /etc/init.d/<filename>`.
|
||||
5. Register the service with `update-rc.d <filename> defaults` on Ubuntu.
|
||||
6. Start the service with `service <filename> start`.
|
||||
7. ???
|
||||
8. Profit!
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- [Vue.js](https://vuejs.org/)
|
||||
- [yunginnanet/sysvinit-service-generator](https://github.com/yunginnanet/sysvinit-service-generator/)
|
||||
17
index.html
Normal file
17
index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>sysvinit service generator</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
4582
package-lock.json
generated
Normal file
4582
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
package.json
Normal file
35
package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "sysvinit-service-generator",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@tsconfig/node20": "^20.1.2",
|
||||
"@types/node": "^20.11.28",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"npm-run-all2": "^6.1.2",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.1.6",
|
||||
"vite-plugin-vue-devtools": "^7.0.18",
|
||||
"vue-tsc": "^2.0.6"
|
||||
}
|
||||
}
|
||||
BIN
public/android-chrome-192x192.png
Normal file
BIN
public/android-chrome-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/android-chrome-512x512.png
Normal file
BIN
public/android-chrome-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
BIN
public/favicon-16x16.png
Normal file
BIN
public/favicon-16x16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 298 B |
BIN
public/favicon-32x32.png
Normal file
BIN
public/favicon-32x32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 535 B |
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
6
public/favicon.txt
Normal file
6
public/favicon.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
This favicon was generated using the following font:
|
||||
|
||||
- Font Title: Inter
|
||||
- Font Author: Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
|
||||
- Font Source: https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfMZhrib2Bg-4.ttf
|
||||
- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL))
|
||||
1
public/site.webmanifest
Normal file
1
public/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||
187
src/App.vue
Normal file
187
src/App.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
let service = defineModel('service', { default: 'my-service' })
|
||||
let description = defineModel('description', { default: 'This command does something' })
|
||||
let username = defineModel('username', { default: 'root' })
|
||||
let command = defineModel('command', { default: '/usr/local/bin/command' })
|
||||
let servicePath = ref('/etc/init.d/' + service.value )
|
||||
let logRotatePath = ref('/etc/logrotate.d/' + service.value)
|
||||
|
||||
let shellCommands = ref(`sudo chmod +x ${servicePath.value} && sudo update-rc.d ${service.value} defaults`)
|
||||
|
||||
let serviceTemplateString = `#!/usr/bin/env sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: <NAME>
|
||||
# Required-Start: $local_fs $network $named $time $syslog
|
||||
# Required-Stop: $local_fs $network $named $time $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Description: <DESCRIPTION>
|
||||
### END INIT INFO
|
||||
|
||||
SCRIPT="<COMMAND>"
|
||||
RUNAS=<USERNAME>
|
||||
|
||||
PIDFILE=/var/run/<NAME>.pid
|
||||
LOGFILE=/var/log/<NAME>.log
|
||||
|
||||
start() {
|
||||
if [ -f $PIDFILE ] && [ -s $PIDFILE ] && kill -0 $(cat $PIDFILE); then
|
||||
echo "Service already running" >&2
|
||||
return 1
|
||||
fi
|
||||
echo 'Starting service...' >&2
|
||||
local CMD="$SCRIPT &> \\"$LOGFILE\\" & echo \\$!"
|
||||
su -c "$CMD" $RUNAS > "$PIDFILE"
|
||||
# Try with this command instead if above does not work
|
||||
# su -s /bin/sh $RUNAS -c "$CMD" > "$PIDFILE"
|
||||
|
||||
sleep 2
|
||||
PID=$(cat $PIDFILE)
|
||||
if pgrep -u $RUNAS -f $NAME > /dev/null
|
||||
then
|
||||
echo "$NAME is now running, the PID is $PID"
|
||||
else
|
||||
echo ''
|
||||
echo "Error! Could not start $NAME!"
|
||||
fi
|
||||
}
|
||||
|
||||
stop() {
|
||||
if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then
|
||||
echo 'Service not running' >&2
|
||||
return 1
|
||||
fi
|
||||
echo 'Stopping service...' >&2
|
||||
kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
|
||||
echo 'Service stopped' >&2
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] "
|
||||
local SURE
|
||||
read SURE
|
||||
if [ "$SURE" = "yes" ]; then
|
||||
stop
|
||||
rm -f "$PIDFILE"
|
||||
echo "Notice: log file was not removed: $LOGFILE" >&2
|
||||
update-rc.d -f $NAME remove
|
||||
rm -fv "$0"
|
||||
else
|
||||
echo "Abort!"
|
||||
fi
|
||||
}
|
||||
|
||||
status() {
|
||||
printf "%-50s" "Checking <NAME>..."
|
||||
if [ -f $PIDFILE ] && [ -s $PIDFILE ]; then
|
||||
PID=$(cat $PIDFILE)
|
||||
if [ -z "$(ps axf | grep \${PID} | grep -v grep)" ]; then
|
||||
printf "%s\\n" "The process appears to be dead but pidfile still exists"
|
||||
else
|
||||
echo "Running, the PID is $PID"
|
||||
fi
|
||||
else
|
||||
printf "%s\\n" "Service not running"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
uninstall)
|
||||
uninstall
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|restart|uninstall}"
|
||||
esac
|
||||
`
|
||||
|
||||
let logRotateString = `/var/log/<NAME>.log {
|
||||
rotate 4
|
||||
weekly
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
}`
|
||||
|
||||
let serviceTemplate = serviceTemplateString
|
||||
.replace(/<NAME>/g, service.value)
|
||||
.replace(/<DESCRIPTION>/g, description.value)
|
||||
.replace(/<USERNAME>/g, username.value)
|
||||
.replace(/<COMMAND>/g, command.value)
|
||||
|
||||
let logRotate = logRotateString.replace(/<NAME>/g, service.value)
|
||||
|
||||
watch([service, description, username, command], ([newService, newDescription, newUsername, newCommand]) => {
|
||||
serviceTemplate = serviceTemplateString
|
||||
.replace(/<NAME>/g, newService)
|
||||
.replace(/<DESCRIPTION>/g, newDescription)
|
||||
.replace(/<USERNAME>/g, newUsername)
|
||||
.replace(/<COMMAND>/g, newCommand)
|
||||
servicePath.value = '/etc/init.d/' + newService
|
||||
logRotate = logRotateString.replace(/<NAME>/g, newService)
|
||||
logRotatePath.value = '/etc/logrotate.d/' + newService
|
||||
shellCommands.value = `sudo chmod +x ${servicePath.value} && sudo update-rc.d ${newService} defaults`
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<h1 class="green">sysvinit service generator</h1>
|
||||
|
||||
<label>
|
||||
Service name:
|
||||
<input type="text" minlength="1" v-model="service" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Description:
|
||||
<input type="text" minlength="1" v-model="description" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Run as user:
|
||||
<input type="text" minlength="1" v-model="username" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Command:
|
||||
<input type="text" minlength="1" v-model="command" />
|
||||
</label>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h3>Generated service script:</h3>
|
||||
<div>Path: <code>{{ servicePath }}</code></div>
|
||||
<textarea style="height: 400px" v-text="serviceTemplate"></textarea>
|
||||
<details>
|
||||
<summary>Logrotate</summary>
|
||||
<div>Path: <code>{{ logRotatePath }}</code></div>
|
||||
<textarea class="just-right noresize" v-text="logRotate"></textarea>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Shell commands to run</summary>
|
||||
<textarea class="just-right noresize" v-text="shellCommands"></textarea>
|
||||
</details>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Created by <a href="https://github.com/ivuorinen">@ivuorinen</a> from Tampere, Finland</p>
|
||||
</footer>
|
||||
</template>
|
||||
82
src/assets/base.css
Normal file
82
src/assets/base.css
Normal file
@@ -0,0 +1,82 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
|
||||
/* semantic color variables for this project */
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition: color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family: Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
102
src/assets/main.css
Normal file
102
src/assets/main.css
Normal file
@@ -0,0 +1,102 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
header {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
input {
|
||||
display: block;
|
||||
margin-top: 1rem;
|
||||
padding: 0.4rem;
|
||||
font-size: 1rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 2.6rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 1px solid var(--color-border);
|
||||
padding-top: 1rem;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
max-width: fit-content;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
border: 1px solid hsla(160, 100%, 37%, 1);
|
||||
border-radius: 5px;
|
||||
background: #222222;
|
||||
color: #f8f8f8;
|
||||
font-family: monospace;
|
||||
|
||||
&.just-right {
|
||||
height: fit-content;
|
||||
min-height: fit-content;
|
||||
max-height: fit-content;
|
||||
}
|
||||
|
||||
&.noresize {
|
||||
resize: none;
|
||||
}
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
6
src/main.ts
Normal file
6
src/main.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
14
tsconfig.app.json
Normal file
14
tsconfig.app.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
tsconfig.node.json
Normal file
19
tsconfig.node.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
18
vite.config.ts
Normal file
18
vite.config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import VueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
VueDevTools(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user