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 (
)
type
CreateEnv
struct
{
Config
string
Config
Dir
string
}
type
HyprEnv
struct
{
...
...
@@ -36,7 +36,7 @@ func InitConfig() error {
Env
.
IsRoot
=
os
.
Geteuid
()
==
0
Env
.
Create
=
&
CreateEnv
{
Config
:
"/etc/ximperdistro/ximperconf/profiles.yaml
"
,
Config
Dir
:
"/etc/ximperdistro/ximperconf/create.d/
"
,
}
if
utils
.
FileExists
(
"/usr/bin/hyprland"
)
{
...
...
create/actions.go
View file @
7a57395c
...
...
@@ -106,8 +106,10 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
// ----- hyprvars -----
for
_
,
v
:=
range
prof
.
HyprVars
{
// ----- hyprland -----
// --------- vars
for
_
,
v
:=
range
prof
.
Hyprland
.
Vars
{
_
,
err
:=
hyprland
.
HyprlandVarGet
(
v
.
Name
)
if
err
==
nil
{
res
.
HyprVars
=
append
(
res
.
HyprVars
,
...
...
@@ -129,8 +131,8 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
// -----
hyprmodules -----
for
_
,
m
:=
range
prof
.
HyprModules
{
// -----
---- modules
for
_
,
m
:=
range
prof
.
Hypr
land
.
Modules
{
if
m
.
Module
==
""
{
res
.
HyprModules
=
append
(
res
.
HyprModules
,
"Пропущен модуль без имени"
)
continue
...
...
@@ -170,8 +172,8 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
// -----
синхронизация раскладок Hyprland-----
if
prof
.
SyncSystemLayouts
&&
!
dryRun
{
// -----
---- синхронизация раскладок Hyprland
if
prof
.
Hyprland
.
Option
.
SyncSystemLayouts
&&
!
dryRun
{
sysLayouts
,
err
:=
hyprland
.
HyprlandGetKeyboardLayouts
()
if
err
!=
nil
{
res
.
SyncSystemLayouts
=
append
(
res
.
SyncSystemLayouts
,
...
...
@@ -210,18 +212,41 @@ func processProfile(prof Profile, dryRun bool, res *Result) {
}
}
func
loadConfig
(
path
string
)
(
*
Config
,
error
)
{
data
,
err
:=
os
.
ReadFile
(
path
)
func
loadConfig
(
dir
string
)
(
*
Config
,
error
)
{
cfg
:=
&
Config
{
Profiles
:
map
[
string
]
Profile
{}}
entries
,
err
:=
os
.
ReadDir
(
dir
)
if
err
!=
nil
{
return
nil
,
err
}
var
cfg
Config
if
err
:=
yaml
.
Unmarshal
(
data
,
&
cfg
);
err
!=
nil
{
return
nil
,
err
for
_
,
e
:=
range
entries
{
if
e
.
IsDir
()
{
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
{
...
...
@@ -403,30 +428,108 @@ func printTree(title string, lines []string) {
fmt
.
Println
()
}
func
createProfile
(
profile
string
,
dryRun
bool
,
res
*
Result
)
error
{
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
Config
)
func
createProfile
(
profileName
string
,
prof
Profile
,
dryRun
bool
,
res
*
Result
)
{
color
.
Green
(
"Создаётся профиль: %s"
,
profileName
)
processProfile
(
prof
,
dryRun
,
res
)
}
func
ShowProfilesInfo
()
{
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
ConfigDir
)
if
err
!=
nil
{
color
.
Red
(
"Не удалось загрузить конфигурацию: %v"
,
err
)
return
err
return
}
prof
,
ok
:=
cfg
.
Profiles
[
profile
]
if
!
ok
{
color
.
Red
(
"Профиль %s не найден"
,
profile
)
return
nil
if
len
(
cfg
.
Profiles
)
==
0
{
color
.
Red
(
"Нет доступных профилей"
)
return
}
color
.
Green
(
"Создаётся профиль: %s"
,
profile
)
processProfile
(
prof
,
dryRun
,
res
)
return
nil
color
.
Blue
(
"Profiles:"
)
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
{
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"
)
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
.
Links
)
printTree
(
"Обновляем"
,
res
.
Replaced
)
...
...
create/commands.go
View file @
7a57395c
...
...
@@ -3,7 +3,6 @@ package create
import
(
"context"
"fmt"
"os/exec"
"ximperconf/config"
"github.com/urfave/cli/v3"
...
...
@@ -20,6 +19,12 @@ func CommandList() *cli.Command {
Aliases
:
[]
string
{
"d"
},
Value
:
false
,
},
&
cli
.
BoolFlag
{
Name
:
"auto"
,
Usage
:
" Automatic profile selection"
,
Aliases
:
[]
string
{
"a"
},
Value
:
false
,
},
},
Action
:
CreateConfCommand
,
ShellComplete
:
ShellCompleteProfiles
,
...
...
@@ -31,21 +36,13 @@ func ShellCompleteProfiles(ctx context.Context, cmd *cli.Command) {
return
}
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
Config
)
cfg
,
err
:=
loadConfig
(
config
.
Env
.
Create
.
Config
Dir
)
if
err
!=
nil
{
return
}
for
profileName
,
profile
:=
range
cfg
.
Profiles
{
show
:=
true
if
profile
.
Binary
!=
""
{
if
_
,
err
:=
exec
.
LookPath
(
profile
.
Binary
);
err
!=
nil
{
show
=
false
}
}
if
show
{
if
ProfileAvailable
(
profile
)
{
fmt
.
Println
(
profileName
)
}
}
...
...
create/struct.go
View file @
7a57395c
...
...
@@ -29,16 +29,27 @@ type HyprModule struct {
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
{
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"`
Links
[]
LinkEntry
`yaml:"links"`
Links
[]
LinkEntry
`yaml:"links
,omitempty
"`
ReleaseReplace
[]
ReleaseReplaceEntry
`yaml:"release-replace,omitempty"`
// ----- hyprland -----
SyncSystemLayouts
bool
`yaml:"sync-system-layouts,omitempty"`
HyprVars
[]
HyprVar
`yaml:"hyprvars,omitempty"`
HyprModules
[]
HyprModule
`yaml:"hyprmodules,omitempty"`
Hyprland
HyprlandEntry
`yaml:"hyprland,omitempty"`
}
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