Advertisement
SpiderLordCoder1st

Untitled

Apr 16th, 2024
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.75 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4. "bufio"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "os/signal"
  10. "path/filepath"
  11. "strings"
  12. "syscall"
  13. "log"
  14. "time"
  15. //"syscall"
  16. "os/exec"
  17. "strconv"
  18. "encoding/json"
  19. "golang.org/x/sys/unix"
  20. "github.com/fsnotify/fsnotify"
  21. "github.com/go-git/go-git/v5"
  22. "github.com/go-git/go-git/v5/config"
  23. )
  24.  
  25. var gitDirectory = "/home/spiderunderurbed/.config/nixos-git-deploy/"
  26. var watchedFiles = make(map[string]bool)
  27.  
  28. type Config struct {
  29. UserAllowed string `json:"UserAllowed"`
  30. FirstTime string `json:"FirstTime"`
  31. }
  32.  
  33. // type Settings struct {
  34. // UserAllowed: "n",
  35. // firstTi
  36. // }
  37. // Function to modify the file within the Git repository
  38. func modifyFile(filename string) error {
  39. // Splits the filename by '/' to get all elements in a path
  40. parts := strings.Split(filename, "/")
  41. // Once you split it, you can find the ACTUAL filename
  42. fileName := parts[len(parts)-1]
  43.  
  44. // Gets the absolute path of the coorosponding git file
  45. gitFilePath := filepath.Join(gitDirectory, fileName)
  46.  
  47. // Read the content of the original file
  48. content, err := ioutil.ReadFile(filename)
  49. if err != nil {
  50. return err
  51. }
  52.  
  53. // TODO: See if go lets you append the newly added content to the file instead of overriting the whole thing with itself?
  54. modifiedContent := string(content)
  55.  
  56. // Write the modified contents back to the file in the Git directory
  57. if err := ioutil.WriteFile(gitFilePath, []byte(modifiedContent), 0644); err != nil {
  58. return err
  59. }
  60.  
  61. // Open the Git repository
  62. r, err := git.PlainOpen(gitDirectory)
  63. if err != nil {
  64. return err
  65. }
  66.  
  67. // Get the worktree
  68. worktree, err := r.Worktree()
  69. if err != nil {
  70. return err
  71. }
  72.  
  73. // Add the modified file to the Git staging area
  74. if _, err := worktree.Add(fileName); err != nil {
  75. return err
  76. }
  77.  
  78. //fmt.Printf("File %s has been successfully modified in the Git repository\n", fileName)
  79. return nil
  80. }
  81.  
  82. // Function to add files to Git repository
  83. func addFilesToGit(files []string, r *git.Repository) error {
  84. worktree, err := r.Worktree()
  85. if err != nil {
  86. return err
  87. }
  88.  
  89. for _, file := range files {
  90. // Check if the file exists
  91. if _, err := os.Stat(file); os.IsNotExist(err) {
  92. fmt.Println("File does not exist:", file)
  93. continue
  94. }
  95.  
  96. // Determine the filename without the path
  97. fileName := filepath.Base(file)
  98.  
  99. // Destination path in the Git directory
  100. destination := filepath.Join(gitDirectory, fileName)
  101.  
  102. // Copy the file to the Git directory
  103. if err := copyFile(file, destination); err != nil {
  104. return err
  105. }
  106.  
  107. // Add the file to the Git repository
  108. _, err := worktree.Add(fileName)
  109. if err != nil {
  110. return err
  111. }
  112. }
  113.  
  114. return nil
  115. }
  116.  
  117. // Function to watch for file changes
  118. func watchChanges(filename string) {
  119. // Check if the file is already being watched
  120. if _, ok := watchedFiles[filename]; ok {
  121. fmt.Printf("File %s is already being watched\n", filename)
  122. return
  123. }
  124.  
  125. // Create a new watcher
  126. watcher, err := fsnotify.NewWatcher()
  127. if err != nil {
  128. fmt.Printf("Error creating watcher for file %s: %v\n", filename, err)
  129. return
  130. }
  131. defer watcher.Close()
  132.  
  133. // Add the file to the watcher
  134. err = watcher.Add(filename)
  135. if err != nil {
  136. fmt.Printf("Error adding file %s to watcher: %v\n", filename, err)
  137. return
  138. }
  139. watchedFiles[filename] = true
  140.  
  141. // Start watching for events
  142. fmt.Printf("Watching for changes in file: %s\n", filename)
  143. for {
  144. select {
  145. case event, ok := <-watcher.Events:
  146. if !ok {
  147. return
  148. }
  149. if event.Op&fsnotify.Write == fsnotify.Write {
  150. //fmt.Printf("File %s has been modified\n", filename)
  151. err := modifyFile(filename)
  152. if err != nil {
  153. fmt.Println("ERROR:", err)
  154. }
  155. }
  156. case err, ok := <-watcher.Errors:
  157. if !ok {
  158. return
  159. }
  160. fmt.Printf("Error watching file %s: %v\n", filename, err)
  161. }
  162. }
  163. }
  164.  
  165. // Function to copy a file
  166. func copyFile(src, dest string) error {
  167. sourceFile, err := os.Open(src)
  168. if err != nil {
  169. return err
  170. }
  171. defer sourceFile.Close()
  172.  
  173. destinationFile, err := os.Create(dest)
  174. if err != nil {
  175. return err
  176. }
  177. defer destinationFile.Close()
  178.  
  179. _, err = io.Copy(destinationFile, sourceFile)
  180. if err != nil {
  181. return err
  182. }
  183.  
  184. return nil
  185. }
  186. func keepAlive(f *os.File, origin string) {
  187. i := 0
  188. for {
  189. // Write string to the named pipe file.
  190. _, err := f.WriteString(fmt.Sprintf("%s: test write times: %d\n", origin, i))
  191. if err != nil {
  192. fmt.Printf("Error writing to file: %v\n", err)
  193. return
  194. }
  195. i++
  196. time.Sleep(time.Second)
  197. }
  198. }
  199.  
  200. func runChildProcess() {
  201. unix.Setpgid(0, 0)
  202. //var stdout bytes.Buffer
  203. // Function to be executed in child process
  204. messages := make(chan string, 10000)
  205. //f := writer("detach.log", "child")
  206. // fmt.Println("TEST")
  207. go Reader("recede.log", "child", messages)
  208. go writer("detach.log", "child", messages)
  209.  
  210. //for {}
  211.  
  212. c := make(chan os.Signal, 1)
  213. signal.Notify(c, os.Interrupt, syscall.SIGTERM)
  214. <-c
  215. //keepAlive(f, "parent")
  216. fmt.Println("Running in child process")
  217. // Sleep for 100 seconds
  218. //time.Sleep(100 * time.Second)
  219. }
  220. func processChildArgs(args []string, messages chan string){
  221. //fmt.Println("child: " + strings.Join(args, " "))
  222. //fmt.Println(args)
  223. //messages <- "test"
  224. }
  225. func processParentArgs(args []string, messages chan string){
  226. //fmt.Println("parent: " + strings.Join(args, " "))
  227. if (args[0] == "watch"){
  228. messages <- "responding " + args[1]
  229. //fmt.Println("+"+args[1]+"+")
  230. go watchChanges(args[1])
  231. }
  232. //fmt.Println(args)
  233. //messages <- "test"
  234. }
  235.  
  236. func Reader(pipeFile string, origin string, messages chan string) {
  237. // Open the named pipe for reading
  238. pipe, err := os.Open(pipeFile)
  239. if os.IsNotExist(err) {
  240. log.Fatalf("Named pipe '%s' does not exist", pipeFile)
  241. } else if os.IsPermission(err) {
  242. log.Fatalf("Insufficient permissions to read named pipe '%s': %s", pipeFile, err)
  243. } else if err != nil {
  244. log.Fatalf("Error while opening named pipe '%s': %s", pipeFile, err)
  245. }
  246. defer pipe.Close()
  247.  
  248. // Infinite loop for reading from the named pipe
  249. //messages <- "We received"
  250. for {
  251. // Read from the named pipe
  252. data := make([]byte, 1024) // Read buffer size
  253. n, err := pipe.Read(data)
  254. if err != nil {
  255. log.Fatalf("Error reading from named pipe '%s': %s", pipeFile, err)
  256. }
  257. input := strings.TrimSpace(string(data[:n]))
  258. args := strings.Split(input, " ")
  259. //fmt.Println(args[0])
  260. if (args[0] == "child:"){
  261. args = args[1:]
  262. //fmt.Println("child message" + args[0])
  263. processChildArgs(args, messages)
  264. } else if (args[0] == "parent:"){
  265. args = args[1:]
  266. //fmt.Println("parent message" + args[0])
  267. processParentArgs(args, messages)
  268. }
  269. //#fmt.Println("data " + string(data[:n]))
  270. // Process the read data
  271. //processData(data[:n], origin, messages)
  272. }
  273. }
  274.  
  275. func writer(pipeFile string, origin string, messages chan string) *os.File {
  276. // Open the file
  277. f, err := os.OpenFile(pipeFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
  278. if err != nil {
  279. fmt.Printf("Error opening file: %v\n", err)
  280. return nil // Return nil if there's an error
  281. }
  282.  
  283. // Continuously wait for messages and write them to the file
  284. for msg := range messages {
  285. //fmt.Println("TEST")
  286. //fmt.Println(msg)
  287. //fmt.Printf(fmt.Sprintf("%s: %s\n", origin, msg))
  288. _, err := f.WriteString(fmt.Sprintf("%s: %s\n", origin, msg + "\n"))
  289. if err != nil {
  290. fmt.Printf("Error writing to file: %v\n", err)
  291. break // Break the loop if there's an error
  292. }
  293. }
  294.  
  295. // Close the file before returning
  296. f.Close()
  297.  
  298. // Return the opened file
  299. return f
  300. }
  301.  
  302.  
  303. func cleanup(messages chan string) {
  304. // Handle SIGINT (Ctrl+C) signal to perform cleanup before exiting
  305. c := make(chan os.Signal, 1)
  306. signal.Notify(c, os.Interrupt, syscall.SIGTERM)
  307.  
  308. // Block until a signal is received
  309. <-c
  310.  
  311. // Close the messages channel to stop writer goroutine
  312. close(messages)
  313.  
  314. // Perform cleanup actions
  315. fmt.Println("Performing cleanup actions...")
  316. // Add your cleanup code here
  317.  
  318. // Exit the program gracefully
  319. os.Exit(0)
  320. }
  321.  
  322. func killProcess(pid int) error {
  323. // Find the process by its PID
  324. proc, err := os.FindProcess(pid)
  325. if err != nil {
  326. return fmt.Errorf("error finding process: %v", err)
  327. }
  328.  
  329. // Check if the process is nil
  330. if proc == nil {
  331. return fmt.Errorf("process with PID %d not found", pid)
  332. }
  333.  
  334. // Send SIGTERM signal to the process
  335. err = proc.Signal(syscall.SIGTERM)
  336. if err != nil {
  337. return fmt.Errorf("error sending SIGTERM signal: %v", err)
  338. }
  339.  
  340. return nil
  341. }
  342. func main() {
  343.  
  344. //Check if there are any command-line arguments
  345. if len(os.Args) > 1 && os.Args[1] == "child" {
  346. // This is the child process
  347. runChildProcess()
  348. return
  349. }
  350.  
  351. reader := bufio.NewReader(os.Stdin)
  352.  
  353. //type Settings struc {
  354.  
  355. configFile := Config{
  356. UserAllowed: "y",
  357. FirstTime: "y",
  358. }
  359.  
  360. rawConfig, err := os.Open("./config.json")
  361. if err != nil {
  362. fmt.Println("Error opening file:", err)
  363. return
  364. }
  365. defer rawConfig.Close()
  366.  
  367. formattedConfig, err := ioutil.ReadAll(rawConfig)
  368. if err != nil {
  369. fmt.Println("Error reading file:", err)
  370. return
  371. }
  372.  
  373. err = json.Unmarshal(formattedConfig, &configFile)
  374. if err != nil {
  375. fmt.Println("Error unmarshalling JSON:", err)
  376. return
  377. }
  378.  
  379. // Reset file cursor to beginning
  380. _, err = rawConfig.Seek(0, 0)
  381. if err != nil {
  382. fmt.Println("Error seeking file:", err)
  383. return
  384. }
  385.  
  386. fomated_config, err := ioutil.ReadAll(rawConfig)
  387. if err != nil {
  388. fmt.Println("Error reading file:", err)
  389. return
  390. }
  391.  
  392. var settings Config
  393. err = json.Unmarshal(fomated_config, &settings)
  394. if err != nil {
  395. fmt.Println("Error unmarshalling JSON:", err)
  396. return
  397. }
  398.  
  399. //fmt.Println(settings)
  400. //fmt.Print(settings)
  401. if (settings.FirstTime == "y"){
  402. // print("user not allowed")
  403. configFile.FirstTime = "n"
  404. fmt.Print(" Hello! This is nixos-git-deploy.\n If allowed, we will spawn backround processes to\n watch for file changes if allowed, and a backround\n process so that if in the event of a crash or deletion\n of the main files the file watchers will be\n deleted, are you ok with this?[Y/n] ")
  405.  
  406. userallow, _ := reader.ReadString('\n')
  407. userallow = strings.TrimSpace(userallow)
  408.  
  409. if (userallow == "n"){
  410. //fmt.Println("User inputted ")
  411. configFile.UserAllowed = "n"
  412. }
  413. jsonData, err := json.Marshal(configFile)
  414. //fmt.Println(jsonData)
  415. if err != nil {
  416. fmt.Println("Error with JSON:", err)
  417. }
  418.  
  419. err = ioutil.WriteFile("./config.json", []byte(jsonData), 0644)
  420. if err != nil {
  421. fmt.Println("Error with file:", err)
  422. }
  423. //err = ioutil.WriteFile("./config.json", []byte(json.Unmarshal([]bytejson.Marshal(configFile))), 0644)
  424. } else {
  425.  
  426. }
  427. if _, err := os.Stat("detach.log"); err == nil {
  428. //fmt.Println("Named pipe", "detach.log", "already exists.")
  429. } else {
  430. err := syscall.Mkfifo("detach.log", 0600)
  431. if err != nil {
  432. fmt.Println("Error wit pipe file:", err)
  433. }
  434. }
  435.  
  436. if _, err := os.Stat("recede.log"); err == nil {
  437. //fmt.Println("Named pipe", "recede.log", "already exists.")
  438. } else {
  439. err := syscall.Mkfifo("recede.log", 0600)
  440. if err != nil {
  441. fmt.Println("Error wit pipe file:", err)
  442. }
  443. }
  444.  
  445. fmt.Print("\n")
  446. cmd := exec.Command("./nixos-git-deploy-go", "child")
  447. // cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
  448.  
  449. // Start the child process
  450. // err := cmd.Start()
  451. // if err != nil {
  452. // fmt.Println("Error starting child process:", err)
  453. // return
  454. // }
  455.  
  456. cmd.Stdout = os.Stdout
  457.  
  458. err = cmd.Start()
  459. if err != nil {
  460. fmt.Println("Error starting child process:", err)
  461. return
  462. }
  463. //go killProcess(cmd.Process.Pid)
  464. if err != nil {
  465. fmt.Println("Error starting child process:", err)
  466. return
  467. }
  468. messages := make(chan string)
  469.  
  470. go cleanup(messages)
  471. fmt.Println(strconv.Itoa(cmd.Process.Pid))
  472.  
  473. go writer("recede.log", "parent", messages)
  474. go Reader("detach.log", "parent", messages)
  475.  
  476. for {
  477. options := []string{"init", "apply", "status", "remove", "upgrade", "add-automatic", "add", "remote-init"}
  478.  
  479. fmt.Println("What do you want to do?")
  480. for i, option := range options {
  481. fmt.Printf("%d. %s\n", i+1, option)
  482. }
  483.  
  484. fmt.Print("Enter your choice (1-8): ")
  485. choice, _ := reader.ReadString('\n')
  486. choice = strings.TrimSpace(choice)
  487. index := -1
  488. fmt.Sscanf(choice, "%d", &index)
  489. if index < 1 || index > len(options) {
  490. fmt.Println("Invalid choice, please try again.")
  491. continue
  492. }
  493.  
  494. switch options[index-1] {
  495. case "init":
  496. if !ifDirectoryExists(gitDirectory + "/.git") {
  497. _, err := git.PlainInit(gitDirectory, false)
  498. if err != nil {
  499. fmt.Println("Error initializing git repository:", err)
  500. continue
  501. }
  502. fmt.Println("Initialized Git repository.")
  503. fmt.Print("Enter the remote (WE ONLY SUPPORT SSH): ")
  504. remote, _ := reader.ReadString('\n')
  505. remote = strings.TrimSpace(remote)
  506. r, err := git.PlainOpen(gitDirectory)
  507. if err != nil {
  508. fmt.Println("Error opening git repository:", err)
  509. continue
  510. }
  511. _, err = r.CreateRemote(&config.RemoteConfig{
  512. Name: "origin",
  513. URLs: []string{remote},
  514. })
  515. if err != nil {
  516. fmt.Println("Error adding remote:", err)
  517. }
  518. } else {
  519. fmt.Println("Git repository already initialized.")
  520. }
  521. case "remote-init":
  522. fmt.Print("Enter the remote (SSH URL): ")
  523. remote, _ := reader.ReadString('\n')
  524. remote = strings.TrimSpace(remote)
  525. r, err := git.PlainOpen(gitDirectory)
  526. if err != nil {
  527. fmt.Println("Error opening git repository:", err)
  528. continue
  529. }
  530. remoteConf := &config.RemoteConfig{
  531. Name: "origin",
  532. URLs: []string{remote},
  533. }
  534. err = r.DeleteRemote("origin")
  535. if err != nil {
  536. fmt.Println("Error deleting remote:", err)
  537. continue
  538. }
  539. _, err = r.CreateRemote(remoteConf)
  540. if err != nil {
  541. fmt.Println("Error adding remote:", err)
  542. }
  543. case "apply":
  544. // Add your logic for "apply" here
  545. case "remove":
  546. // Add your logic for "remove" here
  547. case "upgrade":
  548. // Add your logic for "upgrade" here
  549. case "status":
  550. // Add your logic for "status" here
  551. case "add-automatic":
  552. // Add logic for adding files
  553. fmt.Print("Enter the path of the file(s) you want to add (comma-separated): ")
  554. filesInput, _ := reader.ReadString('\n')
  555. filesInput = strings.TrimSpace(filesInput)
  556. files := strings.Split(filesInput, ",")
  557. //fmt.Println("test")
  558. if git, err := git.PlainOpen(gitDirectory); err == nil {
  559. go func() {
  560. if err := addFilesToGit(files, git); err != nil {
  561. fmt.Println("Error adding files to Git:", err)
  562. } else {
  563. fmt.Printf("Added %d file(s) to Git\n", len(files))
  564. }
  565. }()
  566. //fmt.Println("sending")
  567. // Start file watchers for added files in separate goroutines
  568. for _, file := range files {
  569. //fmt.Println("sending message")
  570. messages <- "watch " + file
  571. //messages <- "test " + file
  572. //go watchChanges(file)
  573. //_, err := f.WriteString(fmt.Sprintf(file, "parent"))
  574. if err != nil {
  575. fmt.Println("Error sending message:", err)
  576. }
  577. //fmt.Println("finished")
  578. }
  579. } else {
  580. fmt.Println("Error opening Git repository:", err)
  581. }
  582. }
  583. }
  584. }
  585.  
  586. // Function to create directory if it doesn't exist
  587. func ensureDirectoryExists(directory string) {
  588. if _, err := os.Stat(directory); os.IsNotExist(err) {
  589. os.MkdirAll(directory, 0755)
  590. }
  591. }
  592.  
  593. // Function to check if directory exists
  594. func ifDirectoryExists(directory string) bool {
  595. _, err := os.Stat(directory)
  596. return !os.IsNotExist(err)
  597. }
  598.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement