• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-autoinstallation / 7347071288

28 Dec 2023 11:13AM UTC coverage: 69.009% (+0.4%) from 68.607%
7347071288

push

github

web-flow
Merge pull request #874 from yast/rubocop_update

Rubocop update

94 of 254 new or added lines in 51 files covered. (37.01%)

22 existing lines in 13 files now uncovered.

6373 of 9235 relevant lines covered (69.01%)

10.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.93
/src/include/autoinstall/classes.rb
1
# File:  clients/autoinst_linuxrc.ycp
2
# Package:  Autoinstallation Configuration System
3
# Summary:   Linuxrc Settings
4
# Authors:  Anas Nashif<nashif@suse.de>
5
#
6
# $Id$
7
module Yast
1✔
8
  module AutoinstallClassesInclude
1✔
9
    def initialize_autoinstall_classes(_include_target)
1✔
10
      textdomain "autoinst"
1✔
11
      Yast.import "Label"
1✔
12
      Yast.import "Popup"
1✔
13
      Yast.import "AutoinstClass"
1✔
14
      Yast.import "XML"
1✔
15
    end
16

17
    # XML_cleanup()
18
    # @return [Boolean]
19
    def XML_cleanup(input, out)
1✔
20
      # Note, inputs should be already valid, so exceptions is not handled here
NEW
21
      ycpin = XML.XMLToYCPFile(input)
×
22
      Builtins.y2debug("Writing clean XML file to  %1, YCP is (%2)", out, ycpin)
×
23
      XML.YCPToXMLFile(:profile, ycpin, out)
×
24
    end
25

26
    # class_dialog_contents()
27
    # @return [Yast::Term]
28
    def class_dialog_contents
1✔
NEW
29
      classes = Builtins.maplist(AutoinstClass.Classes) do |klass|
×
30
        pathtoClass = Builtins.sformat(
×
31
          "%1/%2",
32
          AutoinstConfig.classDir,
33
          Ops.get_string(klass, "name", "Unknown")
34
        )
35
        files_in_class = Convert.to_list(
×
36
          SCR.Read(path(".target.dir"), pathtoClass)
37
        )
NEW
38
        Builtins.y2milestone("class: %1", klass)
×
39
        i = Item(
×
40
          Id(Ops.get_string(klass, "name", "Unknown")),
41
          Ops.get_string(klass, "name", "No name"),
42
          Ops.get_integer(klass, "order", 0),
43
          Builtins.size(files_in_class)
44
        )
45
        deep_copy(i)
×
46
      end
47

48
      contents = VBox(
×
49
        VWeight(
50
          40,
51
          Table(
52
            Id(:table),
53
            Opt(:notify, :immediate),
54
            Header(_("Class Name"), _("Order"), _("Configurations")),
55
            classes
56
          )
57
        ),
58
        VSpacing(1),
59
        VWeight(40, RichText(Id(:description), _("Class Description"))),
60
        VSpacing(1),
61
        HBox(
62
          PushButton(Id(:new), _("Ne&w")),
63
          PushButton(Id(:edit), _("&Edit")),
64
          PushButton(Id(:delete), _("&Delete"))
65
        )
66
      )
67
      deep_copy(contents)
×
68
    end
69

70
    # AddEditClasses()
71
    # Add or Edit a class
72
    # @param mode [Symbol] mode (:new or :edit)
73
    # @param name [String] class name.
74
    def AddEditClasses(mode, name)
1✔
75
      classNames = Builtins.maplist(AutoinstClass.Classes) do |c|
×
76
        Ops.get_string(c, "name", "")
×
77
      end
78

NEW
79
      klass = (AutoinstClass.Classes || []).find { |c| c["name"] == name }
×
NEW
80
      klass ||= {}
×
81

82
      tmp = Builtins.sformat(
×
83
        "%1",
84
        Ops.add(Builtins.size(AutoinstClass.Classes), 1)
85
      )
NEW
86
      order = Builtins.tointeger(Ops.get_string(klass, "order", tmp))
×
87

88
      UI.OpenDialog(
×
89
        Opt(:decorated),
90
        HBox(
91
          HSpacing(0.5),
92
          VBox(
93
            Heading(_("Edit or Create Classes")),
94
            VSpacing(1),
95
            HBox(
96
              TextEntry(
97
                Id(:name),
98
                _("Na&me"),
99
                Ops.get_string(klass, "name", "")
100
              ),
101
              IntField(
102
                Id(:order),
103
                _("Or&der:"),
104
                1,
105
                10,
106
                order
107
              )
108
            ),
109
            MultiLineEdit(
110
              Id(:description),
111
              Opt(:hstretch),
112
              _("Descri&ption:"),
113
              Ops.get_string(klass, "description", "")
114
            ),
115
            VSpacing(1),
116
            ButtonBox(
117
              PushButton(Id(:save), Label.SaveButton),
118
              PushButton(Id(:cancel), Label.CancelButton)
119
            )
120
          ),
121
          HSpacing(0.5)
122
        )
123
      )
124
      UI.ChangeWidget(Id(:name), :Enabled, false) if mode == :edit
×
125
      ret = :none
×
NEW
126
      loop do
×
127
        ret = Convert.to_symbol(UI.UserInput)
×
128
        if ret == :save
×
129
          if Convert.to_string(UI.QueryWidget(Id(:name), :Value)) == ""
×
130
            Popup.Message(_("That name is already used. Select another name."))
×
131
            ret = :again
×
132
            next
×
133
          end
134
          if mode != :edit &&
×
135
              Builtins.contains(classNames, UI.QueryWidget(Id(:name), :Value))
136
            Popup.Message(_("That name is already used. Select another name."))
×
137
            ret = :again
×
138
            next
×
139
          end
140
          name2 = Convert.to_string(UI.QueryWidget(Id(:name), :Value))
×
141
          if checkFileName(name2) != 0 || name2 == ""
×
142
            Popup.Error(invalidFileName)
×
143
            ret = :again
×
144
            next
×
145
          end
146
          newClass = {
147
            "name"        => name2,
×
148
            "order"       => Convert.to_integer(
149
              UI.QueryWidget(Id(:order), :Value)
150
            ),
151
            "description" => Convert.to_string(
152
              UI.QueryWidget(Id(:description), :Value)
153
            )
154
          }
155
          if mode == :new
×
156
            AutoinstClass.Classes = Builtins.add(
×
157
              AutoinstClass.Classes,
158
              newClass
159
            )
160
            SCR.Execute(
×
161
              path(".target.mkdir"),
162
              Ops.add(Ops.add(AutoinstConfig.classDir, "/"), name2)
163
            )
164
          else
165
            AutoinstClass.Classes = Builtins.maplist(AutoinstClass.Classes) do |c|
×
166
              if Ops.get_string(c, "name", "") ==
×
167
                  Convert.to_string(UI.QueryWidget(Id(:name), :Value))
168
                next deep_copy(newClass)
×
169
              else
170
                next deep_copy(c)
×
171
              end
172
            end
173
          end
174
        end
NEW
175
        break if ret == :save || ret == :cancel
×
176
      end
177

178
      UI.CloseDialog
×
179

180
      ret
×
181
    end
182

183
    # Manage Classes
184
    #
185
    def ManageClasses
1✔
186
      Wizard.CreateDialog
×
187
      title = _("Classes")
×
188

189
      help = _(
×
190
        "<p>Use this interface to define classes of control files. </p>\n"
191
      )
192

193
      help = Ops.add(
×
194
        help,
195
        _(
196
          "<p>For example, you can define a class of configurations for\n" \
197
          "a specific  department, group, or site in your company environment.</p>\n"
198
        )
199
      )
200

201
      help = Ops.add(
×
202
        help,
203
        _(
204
          "<p>The order (priority) defines the hierarchy of a class\n" \
205
          "and when it is merged when creating a control file.\n" \
206
          "</p>\n"
207
        )
208
      )
209

210
      Wizard.SetContents(title, class_dialog_contents, help, true, true)
×
211

212
      Wizard.HideAbortButton
×
213
      Wizard.SetNextButton(:next, Label.FinishButton)
×
214

215
      Wizard.HideAbortButton
×
216
      ret = nil
×
NEW
217
      loop do
×
218
        if Builtins.size(AutoinstClass.Classes) == 0
×
219
          UI.ChangeWidget(Id(:edit), :Enabled, false)
×
220
          UI.ChangeWidget(Id(:delete), :Enabled, false)
×
221
        end
222

NEW
223
        klass = Convert.to_string(UI.QueryWidget(Id(:table), :CurrentItem))
×
224
        cl = Builtins.filter(AutoinstClass.Classes) do |c|
×
NEW
225
          Ops.get_string(c, "name", "") == klass
×
226
        end
227
        selected_class = Ops.get_map(cl, 0, {})
×
NEW
228
        if !klass.nil?
×
229
          UI.ChangeWidget(
×
230
            Id(:description),
231
            :Value,
232
            Ops.get_locale(selected_class, "description", _("No Description"))
233
          )
234
        end
235

236
        ret = Convert.to_symbol(UI.UserInput)
×
237

NEW
238
        case ret
×
239
        when :new
UNCOV
240
          AddEditClasses(ret, "")
×
241

242
          Wizard.SetContents(title, class_dialog_contents, help, true, true)
×
243
        when :edit
NEW
244
          if klass.nil?
×
245
            Popup.Message(_("Select at least one class\nto edit.\n"))
×
246
            next
×
247
          end
NEW
248
          AddEditClasses(ret, klass)
×
249
          Wizard.SetContents(title, class_dialog_contents, help, true, true)
×
250
        when :delete
NEW
251
          if klass.nil?
×
252
            Popup.Message(_("Select at least one class\nto delete.\n"))
×
253
            next
×
254
          end
255
          AutoinstClass.Classes = Builtins.filter(AutoinstClass.Classes) do |c|
×
NEW
256
            Ops.get_string(c, "name", "") != klass
×
257
          end
258
          AutoinstClass.deletedClasses = Builtins.add(
×
259
            AutoinstClass.deletedClasses,
260
            klass
261
          )
262

263
          Wizard.SetContents(title, class_dialog_contents, help, true, true)
×
264
        end
NEW
265
        break if ret == :back || ret == :next
×
266
      end
267

268
      AutoinstClass.Save if ret == :next
×
269
      Wizard.CloseDialog
×
270
      Convert.to_symbol(ret)
×
271
    end
272

273
    # GetClassOrder()
274
    # @param name [String] class name
275
    # @return [Fixnum] class order
276
    def GetClassOrder(name)
1✔
277
      order = 0
×
NEW
278
      Builtins.foreach(AutoinstClass.Classes) do |klass|
×
NEW
279
        order = Ops.get_integer(klass, "order", 0) if Ops.get_string(klass, "name", "") == name
×
280
      end
281
      order
×
282
    end
283

284
    # The merge operation
285
    def MergeAll(selected_profiles, base)
1✔
286
      selected_profiles = deep_copy(selected_profiles)
×
287
      tmpdir = AutoinstConfig.tmpDir
×
288
      SCR.Execute(path(".target.mkdir"), tmpdir)
×
289

290
      Profile.Save(Ops.add(tmpdir, "/base_profile.xml")) if base == :current
×
291

292
      error = false
×
293
      skip = false
×
294
      Builtins.foreach(selected_profiles) do |c|
×
295
        pl = Builtins.filter(AutoinstClass.confs) do |cc|
×
296
          Ops.get_string(cc, "name", "") == Ops.get_string(c, "profile", "") &&
×
297
            Ops.get_string(cc, "class", "yyy") ==
298
              Ops.get_string(c, "class", "xxx")
299
        end
300
        profile = Ops.get_map(pl, 0, {})
×
301
        Builtins.y2milestone("Working on profile: %1", profile)
×
302
        if base == :empty && !skip
×
303
          SCR.Execute(
×
304
            path(".target.bash"),
305
            Ops.add(
306
              Ops.add(
307
                Ops.add(
308
                  Ops.add(
309
                    Ops.add(
310
                      Ops.add(
311
                        Ops.add(Ops.add("cp ", AutoinstConfig.classDir), "/"),
312
                        Ops.get_string(profile, "class", "")
313
                      ),
314
                      "/"
315
                    ),
316
                    Ops.get_string(profile, "name", "")
317
                  ),
318
                  "  "
319
                ),
320
                tmpdir
321
              ),
322
              "/base_profile.xml"
323
            )
324
          )
325
          skip = true
×
326
        else
327
          base_text = "empty control file"
×
328
          base_text = "current control file" if base != :empty
×
329

330
          if Ops.get_string(profile, "name", "") != "" && !error
×
331
            Popup.ShowFeedback(
×
332
              Builtins.sformat(
333
                "Merging %1 (%2) with %3 ....",
334
                Ops.get_string(profile, "name", ""),
335
                Ops.get_string(profile, "class", ""),
336
                base_text
337
              ),
338
              ""
339
            )
340

341
            Builtins.y2milestone(
×
342
              "Merging %1 with %2....",
343
              Ops.get_string(profile, "name", ""),
344
              base_text
345
            )
346

347
            xsltret = AutoinstClass.MergeClasses(
×
348
              profile,
349
              Ops.add(tmpdir, "/base_profile.xml"),
350
              "result.xml"
351
            )
352
            if Ops.get_integer(xsltret, "exit", -1) != 0
×
353
              Popup.Error(
×
354
                Builtins.sformat(
355
                  _("Merge failed:\n %1"),
356
                  Ops.get_string(xsltret, "stderr", "error")
357
                )
358
              )
359
              error = true
×
360
            end
361
            XML_cleanup(
×
362
              Ops.add(tmpdir, "/result.xml"),
363
              Ops.add(tmpdir, "/base_profile.xml")
364
            )
365
          else
366
            error = true
×
367
          end
368
        end
369
      end
370

371
      if error
×
372
        Popup.ClearFeedback
×
373
        return false
×
374
      end
375

376
      # Backup file
377
      SCR.Execute(
×
378
        path(".target.bash"),
379
        Ops.add(
380
          Ops.add("cp ", tmpdir),
381
          "/result.xml /var/lib/autoinstall/tmp/autoinst_result.xml"
382
        )
383
      )
384

385
      Profile.ReadXML("/var/lib/autoinstall/tmp/autoinst_result.xml")
×
386
      SCR.Execute(
×
387
        path(".target.remove"),
388
        " /var/lib/autoinstall/tmp/autoinst_result.xml"
389
      )
390
      Popup.ClearFeedback
×
391

392
      true
×
393
    end
394

395
    # Merge Dialog
396
    # @return [Symbol]
397
    def MergeDialog
1✔
398
      Wizard.CreateDialog
×
399
      title = _("Merge Classes")
×
400
      profiles = {}
×
401

NEW
402
      combo = VBox()
×
403
      AutoinstClass.Files
×
404
      Builtins.foreach(AutoinstClass.confs) do |prof|
×
NEW
405
        klass = Ops.get_string(prof, "class", "Default")
×
NEW
406
        ui_list = Ops.get(profiles, klass, [])
×
407
        ui_list = Builtins.add(ui_list, Item(Id("none"), _("None"))) if Builtins.size(ui_list) == 0
×
408
        ui_list = Builtins.add(
×
409
          ui_list,
410
          Item(
411
            Id(Ops.get_string(prof, "name", "Unknown")),
412
            Ops.get_string(prof, "name", "Unknown")
413
          )
414
        )
NEW
415
        Ops.set(profiles, klass, ui_list)
×
416
      end
417

418
      if Ops.greater_than(Builtins.size(profiles), 0)
×
419
        Builtins.foreach(profiles) do |k, v|
×
NEW
420
          combo = Builtins.add(
×
421
            combo,
422
            HBox(
423
              HWeight(
424
                50,
425
                Left(ComboBox(Id(k), Opt(:hstretch, :autoShortcut), k, v))
426
              ),
427
              HWeight(50, Empty())
428
            )
429
          )
430
        end
431
      else
NEW
432
        combo = Left(Label(Id(:emptyclasses), _("No control files defined")))
×
433
      end
434

435
      contents = Top(
×
436
        Left(
437
          VBox(
438
            combo,
439
            VSpacing(),
440
            RadioButtonGroup(
441
              Id(:rbg),
442
              VBox(
443
                Left(
444
                  RadioButton(
445
                    Id(:empty),
446
                    _("&Merge with Empty Control File"),
447
                    true
448
                  )
449
                ),
450
                Left(
451
                  RadioButton(
452
                    Id(:current),
453
                    _("Merge with &Currently-Loaded Control File")
454
                  )
455
                )
456
              )
457
            ),
458
            PushButton(Id(:merge), _("Merge Cla&sses"))
459
          )
460
        )
461
      )
462

463
      help = _(
×
464
        "<p>If you have defined and created <b>\n" \
465
        "classes</b>, you will be able to merge them using this interface to create\n" \
466
        "a new <i>Profile</i>, which will contain information from every class\n" \
467
        "depending on the priority (order) set when\n" \
468
        "creating the classes.</P>\n"
469
      )
470

471
      help = Ops.add(
×
472
        help,
473
        _("<P>To merge the classes, an <b>XSLT</b>\nscript is used.</P>\n")
474
      )
475

476
      Wizard.SetContents(title, contents, help, true, true)
×
477

478
      Wizard.HideAbortButton
×
479

480
      Wizard.SetNextButton(:next, Label.FinishButton)
×
481
      Wizard.DisableNextButton
×
482

483
      ret = nil
×
NEW
484
      loop do
×
485
        ret = UI.UserInput
×
486
        base = Convert.to_symbol(UI.QueryWidget(Id(:rbg), :CurrentButton))
×
487
        n = 0
×
488
        if ret == :merge
×
489
          selected_profiles = []
×
490
          Builtins.foreach(AutoinstClass.confs) do |prof|
×
491
            selected = UI.QueryWidget(
×
492
              Id(Ops.get_string(prof, "class", "")),
493
              :Value
494
            )
495
            if !selected.nil?
×
496
              n = Ops.add(n, 1) if selected != "none"
×
497
              selected_profiles = Builtins.add(
×
498
                selected_profiles,
499
                "order"   => GetClassOrder(Ops.get_string(prof, "class", "")),
500
                "class"   => Ops.get_string(prof, "class", "none"),
501
                "profile" => selected
502
              )
503
            end
504
          end
505

506
          if n == 0
×
507
            min = 1
×
508

509
            min = 2 if base == :empty
×
510

511
            Popup.Error(
×
512
              Builtins.sformat(
513
                _("Select at least %1  configurations\nto perform a merge.\n"),
514
                min
515
              )
516
            )
517
            next
×
518
          end
519

520
          sorted_profiles = Builtins.sort(
×
521
            Builtins.filter(Builtins.toset(selected_profiles)) do |c|
522
              Ops.get_string(c, "profile", "") != "none"
×
523
            end
524
          ) do |x, y|
525
            Ops.less_than(
×
526
              Ops.get_integer(x, "order", 0),
527
              Ops.get_integer(y, "order", 0)
528
            )
529
          end
530
          Builtins.y2debug("Selected Profiles: %1", sorted_profiles)
×
531

532
          if Ops.greater_than(Builtins.size(sorted_profiles), 0)
×
533
            Builtins.y2milestone(
×
534
              "Calling merge with %1 (%2)",
535
              sorted_profiles,
536
              base
537
            )
538
            MergeAll(sorted_profiles, base)
×
539
          end
540

541
          Wizard.EnableNextButton
×
542
        end
NEW
543
        break if ret == :next || ret == :back
×
544
      end
545

546
      Wizard.CloseDialog
×
547
      Convert.to_symbol(ret)
×
548
    end
549

550
    def classConfiguration
1✔
551
      title = _("Class Configuration")
×
552
      help = _(
×
553
        "<p>Choose one or more of the listed classes to which the current control\n" \
554
        "file should belong.</p>\n"
555
      )
556

557
      AutoinstClass.Files
×
558

559
      profiles = {}
×
560

561
      Builtins.foreach(AutoinstClass.confs) do |prof|
×
NEW
562
        klass = Ops.get_string(prof, "class", "default")
×
NEW
563
        ui_list = Ops.get(profiles, klass, [])
×
564
        ui_list = Builtins.add(ui_list, Item(Id("none"), _("None"))) if Builtins.size(ui_list) == 0
×
565
        ui_list = Builtins.add(
×
566
          ui_list,
567
          Item(
568
            Id(Ops.get_string(prof, "name", "Unknown")),
569
            Ops.get_string(prof, "name", "Unknown")
570
          )
571
        )
NEW
572
        Ops.set(profiles, klass, ui_list)
×
573
      end
574

NEW
575
      combo = VBox()
×
576

577
      if Ops.greater_than(Builtins.size(profiles), 0)
×
578
        Builtins.foreach(profiles) do |k, v|
×
NEW
579
          combo = Builtins.add(
×
580
            combo,
581
            Left(ComboBox(Id(k), Opt(:hstretch, :autoShortcut), k, v))
582
          )
583
        end
584
      else
NEW
585
        combo = Left(Label(Id(:emptyclasses), _("No profiles in this class")))
×
586
      end
587

NEW
588
      contents = Top(Left(VBox(combo)))
×
589

590
      Wizard.SetContents(title, contents, help, true, true)
×
591

592
      Wizard.HideAbortButton
×
593
      Wizard.SetNextButton(:next, Label.FinishButton)
×
594

595
      ret = nil
×
596
      _next = nil
×
NEW
597
      loop do
×
598
        ret = UI.UserInput
×
599
        n = 0
×
600
        if ret == :next
×
601
          selected_profiles = []
×
602
          Builtins.foreach(AutoinstClass.confs) do |prof|
×
603
            selected = UI.QueryWidget(
×
604
              Id(Ops.get_string(prof, "class", "")),
605
              :Value
606
            )
607
            if !selected.nil?
×
608
              n = Ops.add(n, 1) if selected != "none"
×
609
              selected_profiles = Builtins.add(
×
610
                selected_profiles,
611
                "class_name"    => Ops.get_string(prof, "class", "none"),
612
                "configuration" => selected
613
              )
614
            end
615
          end
616

617
          if n == 0
×
618
            Popup.Error(_("Select at least one class configuration.\n"))
×
619
            ret = :again
×
620
            next
×
621
          end
622

623
          sorted_profiles = Builtins.filter(Builtins.toset(selected_profiles)) do |c|
×
624
            Ops.get_string(c, "configuration", "") != "none"
×
625
          end
626

627
          Builtins.y2debug("Selected Profiles: %1", sorted_profiles)
×
628
          AutoinstClass.profile_conf = deep_copy(sorted_profiles)
×
629
        end
NEW
630
        break if ret == :next || ret == :back
×
631
      end
UNCOV
632
      Convert.to_symbol(ret)
×
633
    end
634
  end
635
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc