only delete owned mods, mod enable/disable, do not re-extract

This commit is contained in:
Vilsol 2022-06-08 02:36:28 +03:00
parent c32e6134b3
commit 1daf6e9610
6 changed files with 102 additions and 12 deletions

View file

@ -329,12 +329,17 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan InstallUpdate) e
for _, entry := range dir { for _, entry := range dir {
if entry.IsDir() { if entry.IsDir() {
if _, ok := lockfile[entry.Name()]; !ok { if _, ok := lockfile[entry.Name()]; !ok {
if err := os.RemoveAll(filepath.Join(modsDirectory, entry.Name())); err != nil { 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") return errors.Wrap(err, "failed to delete mod directory")
} }
} }
} }
} }
}
completed := 0 completed := 0
for modReference, version := range lockfile { for modReference, version := range lockfile {
@ -384,7 +389,7 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan InstallUpdate) e
downloading = false downloading = false
log.Info().Str("mod_reference", modReference).Str("version", version.Version).Str("link", version.Link).Msg("extracting mod") 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) return errors.Wrap(err, "could not extract "+modReference)
} }

View file

@ -296,3 +296,30 @@ func (p *Profile) Resolve(resolver DependencyResolver, lockFile *LockFile, gameV
return resultLockfile, nil 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,
}
}

View file

@ -144,7 +144,7 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case KeyEnter: case KeyEnter:
if m.status.done { if m.status.done {
if m.parent != nil { if m.parent != nil {
return m.parent, nil return m.parent, m.parent.Init()
} }
} }
return m, nil return m, nil

View file

@ -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 { } else {
items = []list.Item{ items = []list.Item{
utils.SimpleItem[modMenu]{ utils.SimpleItem[modMenu]{

View file

@ -510,47 +510,71 @@ func (c ModsListDelegate) Render(w io.Writer, m list.Model, index int, item list
} }
isInstalled := false isInstalled := false
isDisabled := false
if c.Context != nil { if c.Context != nil {
profile := c.Context.Profiles.Profiles[c.Context.Profiles.SelectedProfile] profile := c.Context.Profiles.Profiles[c.Context.Profiles.SelectedProfile]
if profile != nil { if profile != nil {
if profile.HasMod(realItem.Extra.Mod_reference) { if profile.HasMod(realItem.Extra.Mod_reference) {
isInstalled = true isInstalled = true
isDisabled = !profile.IsModEnabled(realItem.Extra.Mod_reference)
} }
} }
} }
if emptyFilter { if emptyFilter {
if isInstalled { if isInstalled {
if isDisabled {
title = lipgloss.NewStyle().Foreground(lipgloss.Color("220")).Render("✓ " + title)
} else {
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ " + title) title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ " + title)
} }
}
title = s.DimmedTitle.Render(title) title = s.DimmedTitle.Render(title)
} else if isSelected && m.FilterState() != list.Filtering { } else if isSelected && m.FilterState() != list.Filtering {
if isFiltered { if isFiltered {
unmatched := s.SelectedTitle.Inline(true) unmatched := s.SelectedTitle.Inline(true)
matched := unmatched.Copy().Inherit(s.FilterMatch) matched := unmatched.Copy().Inherit(s.FilterMatch)
if isInstalled { if isInstalled {
if isDisabled {
unmatched = unmatched.Foreground(lipgloss.Color("220"))
matched = matched.Foreground(lipgloss.Color("220"))
} else {
unmatched = unmatched.Foreground(lipgloss.Color("40")) unmatched = unmatched.Foreground(lipgloss.Color("40"))
matched = matched.Foreground(lipgloss.Color("40")) matched = matched.Foreground(lipgloss.Color("40"))
} }
}
title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched) title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched)
} }
if isInstalled { if isInstalled {
if isDisabled {
title = lipgloss.NewStyle().Foreground(lipgloss.Color("220")).Render("✓ ") + title
} else {
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title
} }
}
title = s.SelectedTitle.Render(title) title = s.SelectedTitle.Render(title)
} else { } else {
if isFiltered { if isFiltered {
unmatched := s.NormalTitle.Inline(true) unmatched := s.NormalTitle.Inline(true)
matched := unmatched.Copy().Inherit(s.FilterMatch) matched := unmatched.Copy().Inherit(s.FilterMatch)
if isInstalled { if isInstalled {
if isDisabled {
unmatched = unmatched.Foreground(lipgloss.Color("220"))
matched = matched.Foreground(lipgloss.Color("220"))
} else {
unmatched = unmatched.Foreground(lipgloss.Color("40")) unmatched = unmatched.Foreground(lipgloss.Color("40"))
matched = matched.Foreground(lipgloss.Color("40")) matched = matched.Foreground(lipgloss.Color("40"))
} }
}
title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched) title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched)
} }
if isInstalled { if isInstalled {
if isDisabled {
title = lipgloss.NewStyle().Foreground(lipgloss.Color("220")).Render("✓ ") + title
} else {
title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title title = lipgloss.NewStyle().Foreground(lipgloss.Color("40")).Render("✓ ") + title
} }
}
title = s.NormalTitle.Render(title) title = s.NormalTitle.Render(title)
} }

View file

@ -140,7 +140,19 @@ func SHA256Data(f io.Reader) (string, error) {
return hex.EncodeToString(h.Sum(nil)), nil 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 err := os.MkdirAll(location, 0777); err != nil {
if !os.IsExist(err) { if !os.IsExist(err) {
return errors.Wrap(err, "failed to create mod directory: "+location) 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 { if updates != nil {
select { select {
case updates <- GenericUpdate{Progress: 1}: case updates <- GenericUpdate{Progress: 1}: