github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/analytics/dimensions/dimensions.go (about) 1 package dimensions 2 3 import ( 4 "encoding/json" 5 "os" 6 "strings" 7 8 "github.com/ActiveState/cli/internal/constants" 9 "github.com/ActiveState/cli/internal/errs" 10 "github.com/ActiveState/cli/internal/installation/storage" 11 "github.com/ActiveState/cli/internal/instanceid" 12 "github.com/ActiveState/cli/internal/logging" 13 "github.com/ActiveState/cli/internal/multilog" 14 "github.com/ActiveState/cli/internal/osutils" 15 "github.com/ActiveState/cli/internal/output" 16 "github.com/ActiveState/cli/internal/rollbar" 17 "github.com/ActiveState/cli/internal/rtutils/ptr" 18 "github.com/ActiveState/cli/internal/singleton/uniqid" 19 "github.com/ActiveState/cli/pkg/platform/authentication" 20 "github.com/ActiveState/cli/pkg/sysinfo" 21 ) 22 23 type Values struct { 24 Version *string 25 ChannelName *string 26 UserID *string 27 OSName *string 28 OSVersion *string 29 InstallSource *string 30 UniqID *string 31 SessionToken *string 32 UpdateTag *string 33 ProjectNameSpace *string 34 OutputType *string 35 ProjectID *string 36 Flags *string 37 Trigger *string 38 Headless *string 39 InstanceID *string 40 CommitID *string 41 Command *string 42 Sequence *int 43 TargetVersion *string 44 Error *string 45 Message *string 46 CI *bool 47 Interactive *bool 48 ActiveStateCI *bool 49 50 preProcessor func(*Values) error 51 } 52 53 func NewDefaultDimensions(pjNamespace, sessionToken, updateTag string, auth *authentication.Auth) *Values { 54 installSource, err := storage.InstallSource() 55 if err != nil { 56 multilog.Error("Could not detect installSource: %s", errs.JoinMessage(err)) 57 } 58 59 deviceID := uniqid.Text() 60 61 var userIDString string 62 userID := auth.UserID() 63 if userID != nil { 64 userIDString = userID.String() 65 } 66 67 osName := sysinfo.OS().String() 68 osVersion := "unknown" 69 osvInfo, err := sysinfo.OSVersion() 70 if err != nil { 71 multilog.Log(logging.ErrorNoStacktrace, rollbar.Error)("Could not detect osVersion: %v", err) 72 } 73 if osvInfo != nil { 74 osVersion = osvInfo.Version 75 } 76 77 return &Values{ 78 ptr.To(constants.Version), 79 ptr.To(constants.ChannelName), 80 ptr.To(userIDString), 81 ptr.To(osName), 82 ptr.To(osVersion), 83 ptr.To(installSource), 84 ptr.To(deviceID), 85 ptr.To(sessionToken), 86 ptr.To(updateTag), 87 ptr.To(pjNamespace), 88 ptr.To(string(output.PlainFormatName)), 89 ptr.To(""), 90 ptr.To(CalculateFlags()), 91 ptr.To(""), 92 ptr.To(""), 93 ptr.To(instanceid.ID()), 94 ptr.To(""), 95 ptr.To(osutils.ExecutableName()), 96 ptr.To(0), 97 ptr.To(""), 98 ptr.To(""), 99 ptr.To(""), 100 ptr.To(false), 101 ptr.To(false), 102 ptr.To(false), 103 nil, 104 } 105 } 106 107 func (v *Values) Clone() *Values { 108 return &Values{ 109 Version: ptr.Clone(v.Version), 110 ChannelName: ptr.Clone(v.ChannelName), 111 UserID: ptr.Clone(v.UserID), 112 OSName: ptr.Clone(v.OSName), 113 OSVersion: ptr.Clone(v.OSVersion), 114 InstallSource: ptr.Clone(v.InstallSource), 115 UniqID: ptr.Clone(v.UniqID), 116 SessionToken: ptr.Clone(v.SessionToken), 117 UpdateTag: ptr.Clone(v.UpdateTag), 118 ProjectNameSpace: ptr.Clone(v.ProjectNameSpace), 119 OutputType: ptr.Clone(v.OutputType), 120 ProjectID: ptr.Clone(v.ProjectID), 121 Flags: ptr.Clone(v.Flags), 122 Trigger: ptr.Clone(v.Trigger), 123 Headless: ptr.Clone(v.Headless), 124 InstanceID: ptr.Clone(v.InstanceID), 125 CommitID: ptr.Clone(v.CommitID), 126 Command: ptr.Clone(v.Command), 127 Sequence: ptr.Clone(v.Sequence), 128 TargetVersion: ptr.Clone(v.TargetVersion), 129 Error: ptr.Clone(v.Error), 130 Message: ptr.Clone(v.Message), 131 CI: ptr.Clone(v.CI), 132 Interactive: ptr.Clone(v.Interactive), 133 ActiveStateCI: ptr.Clone(v.ActiveStateCI), 134 preProcessor: v.preProcessor, 135 } 136 } 137 138 func (m *Values) Merge(mergeWith ...*Values) { 139 // This is awkward and long, but using mergo was not an option here because it cannot differentiate between 140 // falsy values and nil pointers 141 for _, dim := range mergeWith { 142 if dim.Version != nil { 143 m.Version = dim.Version 144 } 145 if dim.ChannelName != nil { 146 m.ChannelName = dim.ChannelName 147 } 148 if dim.UserID != nil { 149 m.UserID = dim.UserID 150 } 151 if dim.OSName != nil { 152 m.OSName = dim.OSName 153 } 154 if dim.OSVersion != nil { 155 m.OSVersion = dim.OSVersion 156 } 157 if dim.InstallSource != nil { 158 m.InstallSource = dim.InstallSource 159 } 160 if dim.UniqID != nil { 161 m.UniqID = dim.UniqID 162 } 163 if dim.SessionToken != nil { 164 m.SessionToken = dim.SessionToken 165 } 166 if dim.UpdateTag != nil { 167 m.UpdateTag = dim.UpdateTag 168 } 169 if dim.ProjectNameSpace != nil { 170 m.ProjectNameSpace = dim.ProjectNameSpace 171 } 172 if dim.OutputType != nil { 173 m.OutputType = dim.OutputType 174 } 175 if dim.ProjectID != nil { 176 m.ProjectID = dim.ProjectID 177 } 178 if dim.Flags != nil { 179 m.Flags = dim.Flags 180 } 181 if dim.Trigger != nil { 182 m.Trigger = dim.Trigger 183 } 184 if dim.Headless != nil { 185 m.Headless = dim.Headless 186 } 187 if dim.InstanceID != nil { 188 m.InstanceID = dim.InstanceID 189 } 190 if dim.CommitID != nil { 191 m.CommitID = dim.CommitID 192 } 193 if dim.Command != nil { 194 m.Command = dim.Command 195 } 196 if dim.Sequence != nil { 197 m.Sequence = dim.Sequence 198 } 199 if dim.TargetVersion != nil { 200 m.TargetVersion = dim.TargetVersion 201 } 202 if dim.Error != nil { 203 m.Error = dim.Error 204 } 205 if dim.Message != nil { 206 m.Message = dim.Message 207 } 208 if dim.CI != nil { 209 m.CI = dim.CI 210 } 211 if dim.Interactive != nil { 212 m.Interactive = dim.Interactive 213 } 214 if dim.ActiveStateCI != nil { 215 m.ActiveStateCI = dim.ActiveStateCI 216 } 217 if dim.preProcessor != nil { 218 m.preProcessor = dim.preProcessor 219 } 220 } 221 } 222 223 func (v *Values) RegisterPreProcessor(f func(*Values) error) { 224 v.preProcessor = f 225 } 226 227 func (v *Values) PreProcess() error { 228 if v.preProcessor != nil { 229 if err := v.preProcessor(v); err != nil { 230 return errs.Wrap(err, "PreProcessor failed: %s", errs.JoinMessage(err)) 231 } 232 } 233 234 if ptr.From(v.UniqID, "") == "" { 235 return errs.New("device id is unset when creating analytics event") 236 } 237 238 return nil 239 } 240 241 func (v *Values) Marshal() (string, error) { 242 dimMarshalled, err := json.Marshal(v) 243 if err != nil { 244 return "", errs.Wrap(err, "Could not marshal dimensions") 245 } 246 return string(dimMarshalled), nil 247 } 248 249 func CalculateFlags() string { 250 flags := []string{} 251 for _, arg := range os.Args { 252 if strings.HasPrefix(arg, "-") { 253 flags = append(flags, arg) 254 } 255 } 256 return strings.Join(flags, " ") 257 }