Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
ximperconf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
ximperconf
Commits
7a57395c
Verified
Commit
7a57395c
authored
Dec 03, 2025
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
create: update config struct
parent
a751baae
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
208 additions
and
41 deletions
+208
-41
config.go
config/config.go
+2
-2
actions.go
create/actions.go
+127
-24
commands.go
create/commands.go
+8
-11
struct.go
create/struct.go
+15
-4
tools.go
create/tools.go
+56
-0
No files found.
config/config.go
View file @
7a57395c
...
@@ -7,7 +7,7 @@ import (
...
@@ -7,7 +7,7 @@ import (
)
)
type
CreateEnv
struct
{
type
CreateEnv
struct
{
Config
string
Config
Dir
string
}
}
type
HyprEnv
struct
{
type
HyprEnv
struct
{
...
@@ -36,7 +36,7 @@ func InitConfig() error {
...
@@ -36,7 +36,7 @@ func InitConfig() error {
Env
.
IsRoot
=
os
.
Geteuid
()
==
0
Env
.
IsRoot
=
os
.
Geteuid
()
==
0
Env
.
Create
=
&
CreateEnv
{
Env
.
Create
=
&
CreateEnv
{
Config
:
"/etc/ximperdistro/ximperconf/profiles.yaml
"
,
Config
Dir
:
"/etc/ximperdistro/ximperconf/create.d/
"
,
}
}
if
utils
.
FileExists
(
"/usr/bin/hyprland"
)
{
if
utils
.
FileExists
(
"/usr/bin/hyprland"
)
{
...
...
create/actions.go
View file @
7a57395c
...
@@ -106,8 +106,10 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
...
@@ -106,8 +106,10 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
}
}
// ----- hyprvars -----
// ----- hyprland -----
for
_
,
v
:=
range
prof
.
HyprVars
{
// --------- vars
for
_
,
v
:=
range
prof
.
Hyprland
.
Vars
{
_
,
err
:=
hyprland
.
HyprlandVarGet
(
v
.
Name
)
_
,
err
:=
hyprland
.
HyprlandVarGet
(
v
.
Name
)
if
err
==
nil
{
if
err
==
nil
{
res
.
HyprVars
=
append
(
res
.
HyprVars
,
res
.
HyprVars
=
append
(
res
.
HyprVars
,
...
@@ -129,8 +131,8 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
...
@@ -129,8 +131,8 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
// -----
hyprmodules -----
// -----
---- modules
for
_
,
m
:=
range
prof
.
HyprModules
{
for
_
,
m
:=
range
prof
.
Hypr
land
.
Modules
{
if
m
.
Module
==
""
{
if
m
.
Module
==
""
{
res
.
HyprModules
=
append
(
res
.
HyprModules
,
"Пропущен модуль без имени"
)
res
.
HyprModules
=
append
(
res
.
HyprModules
,
"Пропущен модуль без имени"
)
continue
continue
...
@@ -170,8 +172,8 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
...
@@ -170,8 +172,8 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
}
}
// -----
синхронизация раскладок Hyprland-----
// -----
---- синхронизация раскладок Hyprland
if
prof
.
SyncSystemLayouts
&&
!
dryRun
{
if
prof
.
Hyprland
.
Option
.
SyncSystemLayouts
&&
!
dryRun
{
sysLayouts
,
err
:=
hyprland
.
HyprlandGetKeyboardLayouts
()
sysLayouts
,
err
:=
hyprland
.
HyprlandGetKeyboardLayouts
()
if
err
!=
nil
{
if
err
!=
nil
{
res
.
SyncSystemLayouts
=
append
(
res
.
SyncSystemLayouts
,
res
.
SyncSystemLayouts
=
append
(
res
.
SyncSystemLayouts
,
...
@@ -210,18 +212,41 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
...
@@ -210,18 +212,41 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
}
}
func
loadConfig
(
path
string
)
(
*
Config
,
error
)
{
func
loadConfig
(
dir
string
)
(
*
Config
,
error
)
{
data
,
err
:=
os
.
ReadFile
(
path
)
cfg
:=
&
Config
{
Profiles
:
map
[
string
]
Profile
{}}
entries
,
err
:=
os
.
ReadDir
(
dir
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
var
cfg
Config
for
_
,
e
:=
range
entries
{
if
err
:=
yaml
.
Unmarshal
(
data
,
&
cfg
);
err
!=
nil
{
if
e
.
IsDir
()
{
return
nil
,
err
continue
}
name
:=
e
.
Name
()
if
!
strings
.
HasSuffix
(
name
,
".yaml"
)
&&
!
strings
.
HasSuffix
(
name
,
".yml"
)
{
continue
}
path
:=
filepath
.
Join
(
dir
,
name
)
data
,
err
:=
os
.
ReadFile
(
path
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"read %s: %w"
,
name
,
err
)
}
var
p
Profile
if
err
:=
yaml
.
Unmarshal
(
data
,
&
p
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"parse %s: %w"
,
name
,
err
)
}
profileName
:=
strings
.
TrimSuffix
(
name
,
filepath
.
Ext
(
name
))
cfg
.
Profiles
[
profileName
]
=
p
}
}
return
&
cfg
,
nil
return
cfg
,
nil
}
}
func
expandPath
(
path
,
name
string
)
string
{
func
expandPath
(
path
,
name
string
)
string
{
...
@@ -403,30 +428,108 @@ func printTree(title string, lines []string) {
...
@@ -403,30 +428,108 @@ func printTree(title string, lines []string) {
fmt
.
Println
()
fmt
.
Println
()
}
}
func
createProfile
(
profile
string
,
dryRun
bool
,
res
*
Result
)
error
{
func
createProfile
(
profileName
string
,
prof
Profile
,
dryRun
bool
,
res
*
Result
)
{
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
Config
)
color
.
Green
(
"Создаётся профиль: %s"
,
profileName
)
processProfile
(
prof
,
dryRun
,
res
)
}
func
ShowProfilesInfo
()
{
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
ConfigDir
)
if
err
!=
nil
{
if
err
!=
nil
{
color
.
Red
(
"Не удалось загрузить конфигурацию: %v"
,
err
)
color
.
Red
(
"Не удалось загрузить конфигурацию: %v"
,
err
)
return
err
return
}
}
prof
,
ok
:=
cfg
.
Profiles
[
profile
]
if
len
(
cfg
.
Profiles
)
==
0
{
if
!
ok
{
color
.
Red
(
"Нет доступных профилей"
)
color
.
Red
(
"Профиль %s не найден"
,
profile
)
return
return
nil
}
}
color
.
Green
(
"Создаётся профиль: %s"
,
profile
)
color
.
Blue
(
"Profiles:"
)
processProfile
(
prof
,
dryRun
,
res
)
return
nil
statusMap
:=
map
[
bool
]
struct
{
symbol
string
color
func
(
format
string
,
a
...
interface
{})
string
}{
true
:
{
symbol
:
"●"
,
color
:
color
.
GreenString
},
false
:
{
symbol
:
"○"
,
color
:
color
.
RedString
},
}
i
:=
0
for
name
,
profile
:=
range
cfg
.
Profiles
{
available
:=
ProfileAvailable
(
profile
)
info
:=
statusMap
[
available
]
desc
:=
profile
.
Description
if
desc
==
""
{
desc
=
"-"
}
prefix
:=
"├──"
if
i
==
len
(
cfg
.
Profiles
)
-
1
{
prefix
=
"└──"
}
coloredStatus
:=
info
.
color
(
info
.
symbol
)
coloredName
:=
info
.
color
(
name
)
fmt
.
Printf
(
"%s %s %s — %s
\n
"
,
prefix
,
coloredStatus
,
coloredName
,
desc
)
i
++
}
}
}
func
CreateConfCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
func
CreateConfCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
profile
:=
cmd
.
Args
()
.
Get
(
0
)
profile
:=
cmd
.
Args
()
.
Get
(
0
)
auto
:=
cmd
.
Bool
(
"auto"
)
if
profile
==
""
&&
!
auto
{
ShowProfilesInfo
()
return
nil
}
if
auto
{
var
err
error
profile
,
err
=
AutoDetectProfile
()
if
err
!=
nil
{
color
.
Red
(
"Не удалось определить профиль: %v"
,
err
)
return
err
}
color
.
Green
(
"Автоматически выбран профиль: %s"
,
profile
)
}
dryRun
:=
cmd
.
Bool
(
"dry-run"
)
dryRun
:=
cmd
.
Bool
(
"dry-run"
)
res
:=
&
Result
{}
createProfile
(
profile
,
dryRun
,
res
)
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
ConfigDir
)
if
err
!=
nil
{
color
.
Red
(
"Не удалось загрузить конфигурацию: %v"
,
err
)
return
err
}
mainProf
,
ok
:=
cfg
.
Profiles
[
profile
]
if
!
ok
{
color
.
Red
(
"Профиль %s не найден"
,
profile
)
return
fmt
.
Errorf
(
"профиль %s не найден"
,
profile
)
}
for
_
,
depName
:=
range
mainProf
.
Depends
{
depProf
,
ok
:=
cfg
.
Profiles
[
depName
]
if
!
ok
{
color
.
Yellow
(
"Зависимость %s не найдена, пропускаем"
,
depName
)
continue
}
res
:=
&
Result
{}
createProfile
(
depName
,
depProf
,
dryRun
,
res
)
printTree
(
"Копируем"
,
res
.
Copies
)
printTree
(
"Создаём ссылки"
,
res
.
Links
)
printTree
(
"Обновляем"
,
res
.
Replaced
)
printTree
(
"Создаём переменные Hyprland"
,
res
.
HyprVars
)
printTree
(
"Подключаем модули Hyprland"
,
res
.
HyprModules
)
printTree
(
"Синхронизируем раскладку Hyprland"
,
res
.
SyncSystemLayouts
)
}
res
:=
&
Result
{}
createProfile
(
profile
,
mainProf
,
dryRun
,
res
)
printTree
(
"Копируем"
,
res
.
Copies
)
printTree
(
"Копируем"
,
res
.
Copies
)
printTree
(
"Создаём ссылки"
,
res
.
Links
)
printTree
(
"Создаём ссылки"
,
res
.
Links
)
printTree
(
"Обновляем"
,
res
.
Replaced
)
printTree
(
"Обновляем"
,
res
.
Replaced
)
...
...
create/commands.go
View file @
7a57395c
...
@@ -3,7 +3,6 @@ package create
...
@@ -3,7 +3,6 @@ package create
import
(
import
(
"context"
"context"
"fmt"
"fmt"
"os/exec"
"ximperconf/config"
"ximperconf/config"
"github.com/urfave/cli/v3"
"github.com/urfave/cli/v3"
...
@@ -20,6 +19,12 @@ func CommandList() *cli.Command {
...
@@ -20,6 +19,12 @@ func CommandList() *cli.Command {
Aliases
:
[]
string
{
"d"
},
Aliases
:
[]
string
{
"d"
},
Value
:
false
,
Value
:
false
,
},
},
&
cli
.
BoolFlag
{
Name
:
"auto"
,
Usage
:
" Automatic profile selection"
,
Aliases
:
[]
string
{
"a"
},
Value
:
false
,
},
},
},
Action
:
CreateConfCommand
,
Action
:
CreateConfCommand
,
ShellComplete
:
ShellCompleteProfiles
,
ShellComplete
:
ShellCompleteProfiles
,
...
@@ -31,21 +36,13 @@ func ShellCompleteProfiles(ctx context.Context, cmd *cli.Command) {
...
@@ -31,21 +36,13 @@ func ShellCompleteProfiles(ctx context.Context, cmd *cli.Command) {
return
return
}
}
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
Config
)
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
Config
Dir
)
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
for
profileName
,
profile
:=
range
cfg
.
Profiles
{
for
profileName
,
profile
:=
range
cfg
.
Profiles
{
show
:=
true
if
ProfileAvailable
(
profile
)
{
if
profile
.
Binary
!=
""
{
if
_
,
err
:=
exec
.
LookPath
(
profile
.
Binary
);
err
!=
nil
{
show
=
false
}
}
if
show
{
fmt
.
Println
(
profileName
)
fmt
.
Println
(
profileName
)
}
}
}
}
...
...
create/struct.go
View file @
7a57395c
...
@@ -29,16 +29,27 @@ type HyprModule struct {
...
@@ -29,16 +29,27 @@ type HyprModule struct {
IfExec
string
`yaml:"if-exec,omitempty"`
IfExec
string
`yaml:"if-exec,omitempty"`
}
}
type
HyprOptions
struct
{
SyncSystemLayouts
bool
`yaml:"sync-system-layouts,omitempty"`
}
type
HyprlandEntry
struct
{
Option
HyprOptions
`yaml:"options,omitempty"`
Vars
[]
HyprVar
`yaml:"rvars,omitempty"`
Modules
[]
HyprModule
`yaml:"modules,omitempty"`
}
type
Profile
struct
{
type
Profile
struct
{
Binary
string
`yaml:"binary,omitempty"`
Binary
string
`yaml:"binary,omitempty"`
Description
string
`yaml:"description,omitempty"`
Root
bool
`yaml:"root,omitempty"`
Depends
[]
string
`yaml:"depends,omitempty"`
Copy
[]
CopyEntry
`yaml:"copy,omitempty"`
Copy
[]
CopyEntry
`yaml:"copy,omitempty"`
Links
[]
LinkEntry
`yaml:"links"`
Links
[]
LinkEntry
`yaml:"links
,omitempty
"`
ReleaseReplace
[]
ReleaseReplaceEntry
`yaml:"release-replace,omitempty"`
ReleaseReplace
[]
ReleaseReplaceEntry
`yaml:"release-replace,omitempty"`
// ----- hyprland -----
// ----- hyprland -----
SyncSystemLayouts
bool
`yaml:"sync-system-layouts,omitempty"`
Hyprland
HyprlandEntry
`yaml:"hyprland,omitempty"`
HyprVars
[]
HyprVar
`yaml:"hyprvars,omitempty"`
HyprModules
[]
HyprModule
`yaml:"hyprmodules,omitempty"`
}
}
type
Config
struct
{
type
Config
struct
{
...
...
create/tools.go
0 → 100644
View file @
7a57395c
package
create
import
(
"bytes"
"fmt"
"os"
"os/exec"
"strings"
"ximperconf/config"
"github.com/fatih/color"
)
func
ProfileAvailable
(
p
Profile
)
bool
{
allowed
:=
false
if
p
.
Binary
==
""
{
allowed
=
true
}
else
if
_
,
err
:=
exec
.
LookPath
(
p
.
Binary
);
err
==
nil
{
allowed
=
true
}
if
p
.
Root
!=
config
.
Env
.
IsRoot
{
allowed
=
false
}
return
allowed
}
func
AutoDetectProfile
()
(
string
,
error
)
{
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
ConfigDir
)
if
err
!=
nil
{
color
.
Red
(
"Не удалось загрузить конфигурацию: %v"
,
err
)
return
""
,
err
}
for
name
,
profile
:=
range
cfg
.
Profiles
{
if
profile
.
Binary
==
""
||
!
ProfileAvailable
(
profile
)
{
continue
}
cmd
:=
exec
.
Command
(
"pgrep"
,
"-u"
,
fmt
.
Sprintf
(
"%d"
,
os
.
Getuid
()),
"-x"
,
profile
.
Binary
)
var
out
bytes
.
Buffer
cmd
.
Stdout
=
&
out
if
err
:=
cmd
.
Run
();
err
!=
nil
{
continue
}
if
strings
.
TrimSpace
(
out
.
String
())
!=
""
{
return
name
,
nil
}
}
return
""
,
fmt
.
Errorf
(
"не найден запущенный профиль"
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment