only delete owned mods, mod enable/disable, do not re-extract
This commit is contained in:
parent
c32e6134b3
commit
1daf6e9610
6 changed files with 102 additions and 12 deletions
|
@ -329,8 +329,13 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan InstallUpdate) e
|
|||
for _, entry := range dir {
|
||||
if entry.IsDir() {
|
||||
if _, ok := lockfile[entry.Name()]; !ok {
|
||||
if err := os.RemoveAll(filepath.Join(modsDirectory, entry.Name())); err != nil {
|
||||
return errors.Wrap(err, "failed to delete mod directory")
|
||||
modDir := filepath.Join(modsDirectory, entry.Name())
|
||||
_, err := os.Stat(filepath.Join(modDir, ".smm"))
|
||||
if err == nil {
|
||||
log.Info().Str("mod_reference", entry.Name()).Msg("deleting mod")
|
||||
if err := os.RemoveAll(modDir); err != nil {
|
||||
return errors.Wrap(err, "failed to delete mod directory")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -384,7 +389,7 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan InstallUpdate) e
|
|||
downloading = false
|
||||
|
||||
log.Info().Str("mod_reference", modReference).Str("version", version.Version).Str("link", version.Link).Msg("extracting mod")
|
||||
if err := utils.ExtractMod(reader, size, filepath.Join(modsDirectory, modReference), genericUpdates); err != nil {
|
||||
if err := utils.ExtractMod(reader, size, filepath.Join(modsDirectory, modReference), version.Hash, genericUpdates); err != nil {
|
||||
return errors.Wrap(err, "could not extract "+modReference)
|
||||
}
|
||||
|
||||
|
|
|
@ -296,3 +296,30 @@ func (p *Profile) Resolve(resolver DependencyResolver, lockFile *LockFile, gameV
|
|||
|
||||
return resultLockfile, nil
|
||||
}
|
||||
|
||||
func (p *Profile) IsModEnabled(reference string) bool {
|
||||
if p.Mods == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if mod, ok := p.Mods[reference]; ok {
|
||||
return mod.Enabled
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Profile) SetModEnabled(reference string, enabled bool) {
|
||||
if p.Mods == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := p.Mods[reference]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
p.Mods[reference] = ProfileMod{
|
||||
Version: p.Mods[reference].Version,
|
||||
Enabled: enabled,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case KeyEnter:
|
||||
if m.status.done {
|
||||
if m.parent != nil {
|
||||
return m.parent, nil
|
||||
return m.parent, m.parent.Init()
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
|
|
|
@ -44,6 +44,24 @@ func NewModMenu(root components.RootModel, parent tea.Model, mod utils.Mod) tea.
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
if root.GetCurrentProfile().IsModEnabled(mod.Reference) {
|
||||
items = append(items, utils.SimpleItem[modMenu]{
|
||||
ItemTitle: "Disable Mod",
|
||||
Activate: func(msg tea.Msg, currentModel modMenu) (tea.Model, tea.Cmd) {
|
||||
root.GetCurrentProfile().SetModEnabled(mod.Reference, false)
|
||||
return currentModel.parent, currentModel.parent.Init()
|
||||
},
|
||||
})
|
||||
} else {
|
||||
items = append(items, utils.SimpleItem[modMenu]{
|
||||
ItemTitle: "Enable Mod",
|
||||
Activate: func(msg tea.Msg, currentModel modMenu) (tea.Model, tea.Cmd) {
|
||||
root.GetCurrentProfile().SetModEnabled(mod.Reference, true)
|
||||
return currentModel.parent, currentModel.parent.Init()
|
||||
},
|
||||
})
|
||||
}
|
||||
} else {
|
||||
items = []list.Item{
|
||||
utils.SimpleItem[modMenu]{
|
||||
|
|
|
@ -510,18 +510,24 @@ func (c ModsListDelegate) Render(w io.Writer, m list.Model, index int, item list
|
|||
}
|
||||
|
||||
isInstalled := false
|
||||
isDisabled := false
|
||||
if c.Context != nil {
|
||||
profile := c.Context.Profiles.Profiles[c.Context.Profiles.SelectedProfile]
|
||||
if profile != nil {
|
||||
if profile.HasMod(realItem.Extra.Mod_reference) {
|
||||
isInstalled = true
|
||||
isDisabled = !profile.IsModEnabled(realItem.Extra.Mod_reference)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if emptyFilter {
|
||||
if isInstalled {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ " + title)
|
||||
if isDisabled {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("220")).Render("✓ " + title)
|
||||
} else {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ " + title)
|
||||
}
|
||||
}
|
||||
title = s.DimmedTitle.Render(title)
|
||||
} else if isSelected && m.FilterState() != list.Filtering {
|
||||
|
@ -529,13 +535,22 @@ func (c ModsListDelegate) Render(w io.Writer, m list.Model, index int, item list
|
|||
unmatched := s.SelectedTitle.Inline(true)
|
||||
matched := unmatched.Copy().Inherit(s.FilterMatch)
|
||||
if isInstalled {
|
||||
unmatched = unmatched.Foreground(lipgloss.Color("40"))
|
||||
matched = matched.Foreground(lipgloss.Color("40"))
|
||||
if isDisabled {
|
||||
unmatched = unmatched.Foreground(lipgloss.Color("220"))
|
||||
matched = matched.Foreground(lipgloss.Color("220"))
|
||||
} else {
|
||||
unmatched = unmatched.Foreground(lipgloss.Color("40"))
|
||||
matched = matched.Foreground(lipgloss.Color("40"))
|
||||
}
|
||||
}
|
||||
title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched)
|
||||
}
|
||||
if isInstalled {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title
|
||||
if isDisabled {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("220")).Render("✓ ") + title
|
||||
} else {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title
|
||||
}
|
||||
}
|
||||
title = s.SelectedTitle.Render(title)
|
||||
} else {
|
||||
|
@ -543,13 +558,22 @@ func (c ModsListDelegate) Render(w io.Writer, m list.Model, index int, item list
|
|||
unmatched := s.NormalTitle.Inline(true)
|
||||
matched := unmatched.Copy().Inherit(s.FilterMatch)
|
||||
if isInstalled {
|
||||
unmatched = unmatched.Foreground(lipgloss.Color("40"))
|
||||
matched = matched.Foreground(lipgloss.Color("40"))
|
||||
if isDisabled {
|
||||
unmatched = unmatched.Foreground(lipgloss.Color("220"))
|
||||
matched = matched.Foreground(lipgloss.Color("220"))
|
||||
} else {
|
||||
unmatched = unmatched.Foreground(lipgloss.Color("40"))
|
||||
matched = matched.Foreground(lipgloss.Color("40"))
|
||||
}
|
||||
}
|
||||
title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched)
|
||||
}
|
||||
if isInstalled {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title
|
||||
if isDisabled {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("220")).Render("✓ ") + title
|
||||
} else {
|
||||
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title
|
||||
}
|
||||
}
|
||||
title = s.NormalTitle.Render(title)
|
||||
}
|
||||
|
|
18
utils/io.go
18
utils/io.go
|
@ -140,7 +140,19 @@ func SHA256Data(f io.Reader) (string, error) {
|
|||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func ExtractMod(f io.ReaderAt, size int64, location string, updates chan GenericUpdate) error {
|
||||
func ExtractMod(f io.ReaderAt, size int64, location string, hash string, updates chan GenericUpdate) error {
|
||||
hashFile := filepath.Join(location, ".smm")
|
||||
hashBytes, err := os.ReadFile(hashFile)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return errors.Wrap(err, "failed to read .smm mod hash file")
|
||||
}
|
||||
} else {
|
||||
if hash == string(hashBytes) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(location, 0777); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return errors.Wrap(err, "failed to create mod directory: "+location)
|
||||
|
@ -181,6 +193,10 @@ func ExtractMod(f io.ReaderAt, size int64, location string, updates chan Generic
|
|||
}
|
||||
}
|
||||
|
||||
if err := os.WriteFile(hashFile, []byte(hash), 0777); err != nil {
|
||||
return errors.Wrap(err, "failed to write .smm mod hash file")
|
||||
}
|
||||
|
||||
if updates != nil {
|
||||
select {
|
||||
case updates <- GenericUpdate{Progress: 1}:
|
||||
|
|
Loading…
Reference in a new issue