Skip to content

Commit 7f2b338

Browse files
committed
Merge branch 'master' into CP-1084
2 parents 7ba6ee9 + f25d8e3 commit 7f2b338

File tree

30 files changed

+782
-126
lines changed

30 files changed

+782
-126
lines changed

cmd/state-installer/cmd.go

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type Params struct {
4848
activateDefault *project.Namespaced
4949
showVersion bool
5050
nonInteractive bool
51+
configSettings []string
5152
}
5253

5354
func newParams() *Params {
@@ -71,13 +72,14 @@ func main() {
7172
exitCode = 1
7273
}
7374

75+
if err := events.WaitForEvents(5*time.Second, rollbar.Wait, an.Wait, logging.Close); err != nil {
76+
logging.Warning("state-installer failed to wait for events: %v", err)
77+
}
78+
7479
if cfg != nil {
7580
events.Close("config", cfg.Close)
7681
}
7782

78-
if err := events.WaitForEvents(5*time.Second, rollbar.Wait, an.Wait, logging.Close); err != nil {
79-
logging.Warning("state-installer failed to wait for events: %v", err)
80-
}
8183
os.Exit(exitCode)
8284
}()
8385

@@ -194,6 +196,11 @@ func main() {
194196
Value: &params.showVersion,
195197
},
196198
{Name: "non-interactive", Shorthand: "n", Hidden: true, Value: &params.nonInteractive}, // don't prompt
199+
{
200+
Name: "config-set",
201+
Description: "Set config values in 'key=value' format, can be specified multiple times",
202+
Value: &params.configSettings,
203+
},
197204
// The remaining flags are for backwards compatibility (ie. we don't want to error out when they're provided)
198205
{Name: "channel", Hidden: true, Value: &garbageString},
199206
{Name: "bbb", Shorthand: "b", Hidden: true, Value: &garbageString},
@@ -328,13 +335,26 @@ func execute(out output.Outputer, cfg *config.Instance, an analytics.Dispatcher,
328335
out.Print(fmt.Sprintf("State Tool Package Manager is already installed at [NOTICE]%s[/RESET]. To reinstall use the [ACTIONABLE]--force[/RESET] flag.", installPath))
329336
an.Event(anaConst.CatInstallerFunnel, "already-installed")
330337
params.isUpdate = true
338+
339+
// Apply config settings even when already installed
340+
if err := applyConfigSettings(cfg, params.configSettings); err != nil {
341+
return errs.Wrap(err, "Failed to apply config settings")
342+
}
343+
331344
return postInstallEvents(out, cfg, an, params)
332345
}
333346

334347
if err := installOrUpdateFromLocalSource(out, cfg, an, payloadPath, params); err != nil {
335348
return err
336349
}
337350
storeInstallSource(params.sourceInstaller)
351+
352+
// Apply config settings after installation but before post-install events
353+
// This ensures the State Tool's config is properly set up
354+
if err := applyConfigSettings(cfg, params.configSettings); err != nil {
355+
return errs.Wrap(err, "Failed to apply config settings")
356+
}
357+
338358
return postInstallEvents(out, cfg, an, params)
339359
}
340360

@@ -501,3 +521,44 @@ func assertCompatibility() error {
501521

502522
return nil
503523
}
524+
525+
func applyConfigSettings(cfg *config.Instance, configSettings []string) error {
526+
for _, setting := range configSettings {
527+
setting = strings.TrimSpace(setting)
528+
if setting == "" {
529+
continue // Skip empty settings
530+
}
531+
if err := applyConfigSetting(cfg, setting); err != nil {
532+
return errs.Wrap(err, "Failed to apply config setting: %s", setting)
533+
}
534+
}
535+
return nil
536+
}
537+
538+
func applyConfigSetting(cfg *config.Instance, setting string) error {
539+
var key, valueStr string
540+
541+
if strings.Contains(setting, "=") {
542+
parts := strings.SplitN(setting, "=", 2)
543+
if len(parts) == 2 {
544+
key = strings.TrimSpace(parts[0])
545+
valueStr = strings.TrimSpace(parts[1])
546+
}
547+
}
548+
549+
if key == "" || valueStr == "" {
550+
return locale.NewInputError("err_config_invalid_format", "Config setting must be in 'key=value' format: {{.V0}}", setting)
551+
}
552+
553+
// Store the raw string value without type validation since config options
554+
// are not yet registered in the installer context
555+
err := cfg.Set(key, valueStr)
556+
if err != nil {
557+
// Log the error but don't fail the installation for config issues
558+
logging.Warning("Could not set config value %s=%s: %s", key, valueStr, errs.JoinMessage(err))
559+
return locale.WrapError(err, "err_config_set", "Could not set value {{.V0}} for key {{.V1}}", valueStr, key)
560+
}
561+
562+
logging.Debug("Config setting applied: %s=%s", key, valueStr)
563+
return nil
564+
}

cmd/state-mcp/internal/registry/tools.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ func DownloadLogsTool() Tool {
9696
}
9797

9898
runner := downloadlogs.New(p)
99-
params := downloadlogs.NewParams(url)
99+
params := downloadlogs.NewParams()
100+
params.LogUrl = url
100101
err = runner.Run(params)
101102
if err != nil {
102103
return mcp.NewToolResultError(fmt.Sprintf("error downloading logs: %s", errs.JoinMessage(err))), nil

cmd/state-remote-installer/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func execute(out output.Outputer, prompt prompt.Prompter, cfg *config.Instance,
208208
version = fmt.Sprintf("%s (%s)", version, channel)
209209
}
210210

211-
update := updater.NewUpdateInstaller(an, availableUpdate)
211+
update := updater.NewUpdateInstaller(cfg, an, availableUpdate)
212212
out.Fprint(os.Stdout, locale.Tl("remote_install_downloading", "• Downloading State Tool version [NOTICE]{{.V0}}[/RESET]... ", version))
213213
tmpDir, err := update.DownloadAndUnpack()
214214
if err != nil {

cmd/state-svc/internal/notifications/notifications.go

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/ActiveState/cli/internal/config"
1212
"github.com/ActiveState/cli/internal/constants"
1313
"github.com/ActiveState/cli/internal/errs"
14-
"github.com/ActiveState/cli/internal/fileutils"
1514
"github.com/ActiveState/cli/internal/graph"
1615
"github.com/ActiveState/cli/internal/httputil"
1716
"github.com/ActiveState/cli/internal/logging"
@@ -21,8 +20,14 @@ import (
2120
auth "github.com/ActiveState/cli/pkg/platform/authentication"
2221
"github.com/ActiveState/cli/pkg/sysinfo"
2322
"github.com/blang/semver"
23+
24+
configMediator "github.com/ActiveState/cli/internal/mediators/config"
2425
)
2526

27+
func init() {
28+
configMediator.RegisterOption(constants.NotificationsURLConfig, configMediator.String, "")
29+
}
30+
2631
const ConfigKeyLastReport = "notifications.last_reported"
2732

2833
type Notifications struct {
@@ -48,11 +53,11 @@ func New(cfg *config.Instance, auth *auth.Auth) (*Notifications, error) {
4853
defer func() {
4954
panics.LogAndPanic(recover(), debug.Stack())
5055
}()
51-
resp, err := fetch()
56+
resp, err := fetch(cfg)
5257
return resp, err
5358
})
5459

55-
return &Notifications{
60+
notifications := &Notifications{
5661
baseParams: &ConditionParams{
5762
OS: sysinfo.OS().String(),
5863
OSVersion: NewVersionFromSysinfo(osVersion),
@@ -62,7 +67,20 @@ func New(cfg *config.Instance, auth *auth.Auth) (*Notifications, error) {
6267
cfg: cfg,
6368
auth: auth,
6469
poll: poll,
65-
}, nil
70+
}
71+
72+
configMediator.AddListener(constants.NotificationsURLConfig, func() {
73+
notifications.poll.Close()
74+
notifications.poll = poller.New(10*time.Minute, func() (interface{}, error) {
75+
defer func() {
76+
panics.LogAndPanic(recover(), debug.Stack())
77+
}()
78+
resp, err := fetch(cfg)
79+
return resp, err
80+
})
81+
})
82+
83+
return notifications, nil
6684
}
6785

6886
func (m *Notifications) Close() error {
@@ -168,8 +186,7 @@ func check(params *ConditionParams, notifications []*graph.NotificationInfo, las
168186
// Check if message is within date range
169187
inRange, err := notificationInDateRange(notification, baseTime)
170188
if err != nil {
171-
logging.Warning("Could not check if notification %s is in date range: %v", notification.ID, err)
172-
continue
189+
return nil, errs.Wrap(err, "Could not check if notification %s is in date range", notification.ID)
173190
}
174191
if !inRange {
175192
logging.Debug("Skipping notification %s as it is outside of its date range", notification.ID)
@@ -198,17 +215,36 @@ func check(params *ConditionParams, notifications []*graph.NotificationInfo, las
198215
return filteredNotifications, nil
199216
}
200217

201-
func fetch() ([]*graph.NotificationInfo, error) {
218+
func fetch(cfg *config.Instance) ([]*graph.NotificationInfo, error) {
202219
var body []byte
203220
var err error
204221

205-
if v := os.Getenv(constants.NotificationsOverrideEnvVarName); v != "" {
206-
body, err = fileutils.ReadFile(v)
222+
var (
223+
notificationsURL string
224+
225+
envURL = os.Getenv(constants.NotificationsOverrideEnvVarName)
226+
configURL = cfg.GetString(constants.NotificationsURLConfig)
227+
)
228+
229+
switch {
230+
case envURL != "":
231+
notificationsURL = envURL
232+
case configURL != "":
233+
notificationsURL = configURL
234+
default:
235+
notificationsURL = constants.NotificationsInfoURL
236+
}
237+
238+
logging.Debug("Fetching notifications from %s", notificationsURL)
239+
// Check if this is a local file path (when using environment override)
240+
if envURL != "" {
241+
body, err = os.ReadFile(notificationsURL)
207242
if err != nil {
208-
return nil, errs.Wrap(err, "Could not read notifications override file")
243+
return nil, errs.Wrap(err, "Could not read notifications file")
209244
}
210245
} else {
211-
body, err = httputil.Get(constants.NotificationsInfoURL)
246+
// Use HTTP client for remote URLs
247+
body, err = httputil.Get(notificationsURL)
212248
if err != nil {
213249
return nil, errs.Wrap(err, "Could not fetch notifications information")
214250
}

cmd/state/autoupdate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func autoUpdate(svc *model.SvcModel, args []string, childCmd *captain.Command, c
5353
}
5454

5555
avUpdate := updater.NewAvailableUpdate(upd.Channel, upd.Version, upd.Platform, upd.Path, upd.Sha256, "")
56-
up := updater.NewUpdateInstaller(an, avUpdate)
56+
up := updater.NewUpdateInstaller(cfg, an, avUpdate)
5757
if !up.ShouldInstall() {
5858
logging.Debug("Update is not needed")
5959
return false, nil

cmd/state/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ func main() {
9797
// Configuration options
9898
// This should only be used if the config option is not exclusive to one package.
9999
configMediator.RegisterOption(constants.OptinBuildscriptsConfig, configMediator.Bool, false)
100+
configMediator.RegisterOption(constants.NotificationsURLConfig, configMediator.String, "")
100101

101102
// Set up our output formatter/writer
102103
outFlags := parseOutputFlags(os.Args)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ require (
175175
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
176176
github.com/tklauser/go-sysconf v0.3.12 // indirect
177177
github.com/tklauser/numcpus v0.6.1 // indirect
178-
github.com/ulikunitz/xz v0.5.11 // indirect
178+
github.com/ulikunitz/xz v0.5.14 // indirect
179179
github.com/valyala/bytebufferpool v1.0.0 // indirect
180180
github.com/valyala/fasttemplate v1.2.2 // indirect
181181
github.com/xanzy/ssh-agent v0.3.3 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,8 +679,8 @@ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9f
679679
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
680680
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
681681
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
682-
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
683-
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
682+
github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg=
683+
github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
684684
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
685685
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
686686
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=

installers/install.ps1

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,29 @@ function getopt([string] $opt, [string] $default, [string[]] $arr)
4141
return $default
4242
}
4343

44+
# Collect all instances of a flag (for flags that can appear multiple times)
45+
function getopt_all([string] $opt, [string[]] $arr)
46+
{
47+
$result = @()
48+
for ($i = 0; $i -lt $arr.Length; $i++)
49+
{
50+
$arg = $arr[$i]
51+
if ($arg -eq $opt -and ($i + 1) -lt $arr.Length)
52+
{
53+
$value = $arr[$i + 1]
54+
if ($value -and -not $value.StartsWith("-"))
55+
{
56+
$result += $opt
57+
$result += $value
58+
}
59+
}
60+
}
61+
return $result
62+
}
63+
4464
$script:CHANNEL = getopt "-b" $script:CHANNEL $args
4565
$script:VERSION = getopt "-v" $script:VERSION $args
66+
$script:CONFIG_SET_ARGS = getopt_all "--config-set" $args
4667

4768
function download([string] $url, [string] $out)
4869
{
@@ -269,7 +290,30 @@ $PSDefaultParameterValues['*:Encoding'] = 'utf8'
269290
# Run the installer.
270291
$env:ACTIVESTATE_SESSION_TOKEN = $script:SESSION_TOKEN_VALUE
271292
setShellOverride
272-
& $exePath $args --source-installer="install.ps1"
293+
294+
# Build installer arguments by reconstructing the command line properly
295+
$cmdArgs = @()
296+
297+
# Add non-config-set arguments first
298+
for ($i = 0; $i -lt $args.Length; $i++) {
299+
if ($args[$i] -eq "--config-set" -and ($i + 1) -lt $args.Length) {
300+
# Skip the --config-set flag and its value, we'll add them back from our processed array
301+
$i++ # Skip the value too
302+
} else {
303+
$cmdArgs += $args[$i]
304+
}
305+
}
306+
307+
# Add the processed config-set arguments (pass through without comma splitting - let Go handle it)
308+
if ($script:CONFIG_SET_ARGS -and $script:CONFIG_SET_ARGS.Length -gt 0) {
309+
$cmdArgs += $script:CONFIG_SET_ARGS
310+
}
311+
312+
# Add the source installer flag
313+
$cmdArgs += "--source-installer=install.ps1"
314+
315+
# Execute with the properly constructed arguments
316+
& $exePath @cmdArgs
273317
$success = $?
274318
if (Test-Path env:ACTIVESTATE_SESSION_TOKEN)
275319
{

installers/install.sh

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ DOWNLOADEXT=".tar.gz"
1717
BINARYEXT=""
1818
SHA256SUM="sha256sum"
1919

20-
SESSION_TOKEN_VERIFY="{TOKEN""}"
20+
SESSION_TOKEN_VERIFY="{TOKEN}"
2121
SESSION_TOKEN="{TOKEN}"
2222
SESSION_TOKEN_VALUE=""
2323

@@ -36,8 +36,30 @@ getopt() {
3636
echo $default
3737
}
3838

39+
# Collect all instances of a flag (for flags that can appear multiple times)
40+
getopt_all() {
41+
opt=$1; shift
42+
result=""
43+
i=0
44+
for arg in $@; do
45+
i=$((i + 1))
46+
if [ "${arg}" = "$opt" ]; then
47+
value=$(echo "$@" | cut -d' ' -f$(($i + 1)))
48+
if [ -n "$value" ] && [ "${value#-}" = "$value" ]; then # ensure value doesn't start with -
49+
if [ -n "$result" ]; then
50+
result="$result $opt $value"
51+
else
52+
result="$opt $value"
53+
fi
54+
fi
55+
fi
56+
done
57+
echo $result
58+
}
59+
3960
CHANNEL=$(getopt "-b" "$CHANNEL" $@)
4061
VERSION=$(getopt "-v" "$VERSION" $@)
62+
CONFIG_SET_ARGS=$(getopt_all "--config-set" $@)
4163

4264
if [ -z "${TERM}" ] || [ "${TERM}" = "dumb" ]; then
4365
OUTPUT_OK=""
@@ -205,7 +227,7 @@ progress_done
205227
echo ""
206228

207229
# Run the installer.
208-
ACTIVESTATE_SESSION_TOKEN=$SESSION_TOKEN_VALUE $INSTALLERTMPDIR/$INSTALLERNAME$BINARYEXT "$@" --source-installer="install.sh"
230+
ACTIVESTATE_SESSION_TOKEN=$SESSION_TOKEN_VALUE $INSTALLERTMPDIR/$INSTALLERNAME$BINARYEXT "$@" $CONFIG_SET_ARGS --source-installer="install.sh"
209231

210232
# Remove temp files
211233
rm -r $INSTALLERTMPDIR

0 commit comments

Comments
 (0)