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

yast / yast-packager / 6250068267

20 Sep 2023 02:29PM UTC coverage: 37.38% (-0.01%) from 37.39%
6250068267

push

github

web-flow
Merge pull request #642 from yast/service_fix_sp6

[SLE-15-SP6] Properly save the repo file (bsc#1214135)

3 of 3 new or added lines in 1 file covered. (100.0%)

4329 of 11581 relevant lines covered (37.38%)

23.68 hits per line

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

14.55
/src/lib/packager/clients/repositories.rb
1
# ------------------------------------------------------------------------------
2
# Copyright (c) 2017 SUSE LLC
3
#
4
# This program is free software; you can redistribute it and/or modify it under
5
# the terms of version 2 of the GNU General Public License as published by the
6
# Free Software Foundation.
7
#
8
# This program is distributed in the hope that it will be useful, but WITHOUT
9
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11
#
12
# ------------------------------------------------------------------------------
13

14
Yast.import "Pkg"
1✔
15
Yast.import "UI"
1✔
16

17
Yast.import "Confirm"
1✔
18
Yast.import "Mode"
1✔
19
Yast.import "PackageCallbacks"
1✔
20
Yast.import "PackageLock"
1✔
21
Yast.import "Report"
1✔
22
# SourceManager overlaps quite a bit with inst_source,
23
# so far we only use it for ZMD sync, TODO refactor better
24
Yast.import "SourceManager"
1✔
25
Yast.import "SourceDialogs"
1✔
26
Yast.import "Wizard"
1✔
27

28
Yast.import "Installation"
1✔
29
Yast.import "Label"
1✔
30
Yast.import "Popup"
1✔
31
Yast.import "Sequencer"
1✔
32
Yast.import "CommandLine"
1✔
33
Yast.import "Progress"
1✔
34
Yast.import "Directory"
1✔
35
Yast.import "URL"
1✔
36

37
module Yast
1✔
38
  # Interface for repository management
39
  class RepositoriesClient < Client
1✔
40
    include Yast::Logger
1✔
41

42
    NO_SERVICE = :no_service
1✔
43
    NO_SERVICE_ITEM = :no_service_item
1✔
44

45
    def import_modules
1✔
46
      Yast.import "Pkg"
×
47
      Yast.import "UI"
×
48

49
      Yast.include self, "packager/inst_source_dialogs.rb"
×
50
      Yast.include self, "packager/key_manager_dialogs.rb"
×
51
      Yast.include self, "packager/repositories_include.rb"
×
52
    end
53

54
    def initialize
1✔
55
      super
14✔
56
      textdomain "packager"
14✔
57

58
      @full_mode = false
14✔
59

60
      # cache for textmode value
61
      @text_mode = nil
14✔
62

63
      @sourcesToDelete = []
14✔
64
      @reposFromDeletedServices = []
14✔
65

66
      # default (minimal) priority of a repository
67
      @default_priority = 99
14✔
68

69
      # use a longer label in wide terminals, assume that in Qt the
70
      # longer label always fits
71
      @priority_label = if textmode && UI.GetDisplayInfo["Width"].to_i < 120
14✔
72
        # TRANSLATORS: a widget label for repository priority
73
        # (the short version for small screens)
74
        _("&Priority")
×
75
      else
76
        # TRANSLATORS: a widget label for repository priority
77
        # (the longer version for larger screens).
78
        # The priority meaning is a bit misleading
79
        # therefore display an extra hint for the users.
80
        #
81
        # NOTE: Still keep the label as short as possible, it's used for
82
        # terminals wider than the usual 80x25 (width >= 120) but there still
83
        # might not be enough space for a too long label, do not use more than
84
        # about 50 characters.
85
        _("&Priority (higher number = lower priority)")
14✔
86
      end
87

88
      @keeppackages_label = _("Keep Downloaded Packages")
14✔
89

90
      # current view:
91
      # selected service (or empty) if all services are selected
92
      @displayed_service = ""
14✔
93
      # service/repository view flag
94
      @repository_view = true
14✔
95

96
      # remember the original selected URL scheme
97
      @selected_url_scheme = ""
14✔
98

99
      @cmdline_description = {
14✔
100
        "id"         => "inst_source",
101
        # Command line help text for the repository module, %1 is "zypper"
102
        "help"       => Builtins.sformat(
103
          _(
104
            "Installation Repositories - This module does not support the command line " \
105
            "interface, use '%1' instead."
106
          ),
107
          "zypper"
108
        ),
109
        "guihandler" => fun_ref(method(:StartInstSource), "symbol ()")
110
      }
111

112
      # list of repositories that was already informed to the user that they are
113
      # managed by service
114
      @services_repos = []
14✔
115
    end
116

117
    def main
1✔
118
      import_modules
×
119

120
      if WFM.Args == [:sw_single_mode]
×
121
        Builtins.y2milestone("Started from sw_single, switching the mode")
×
122

123
        @full_mode = true
×
124
        @ret = StartInstSource()
×
125

126
        # load objects from the new repositories
127
        Pkg.SourceLoad if @ret != :abort
×
128

129
        return deep_copy(@ret)
×
130
      end
131

132
      if WFM.Args == ["refresh-enabled"]
×
133
        Builtins.y2milestone("Refresh enabled option set")
×
134
        return StartInstSource()
×
135
      end
136

137
      CommandLine.Run(@cmdline_description)
×
138
    end
139

140
    def textmode
1✔
141
      if @text_mode.nil?
14✔
142
        @text_mode = if Mode.commandline
14✔
143
          true
×
144
        else
145
          Ops.get_boolean(UI.GetDisplayInfo, "TextMode", false)
14✔
146
        end
147
      end
148

149
      @text_mode
14✔
150
    end
151

152
    def RemoveDeletedAddNewRepos
1✔
153
      ret = []
×
154

155
      current_sources = Pkg.SourceGetCurrent(false)
×
156
      known_repos = []
×
157
      deleted_repos = []
×
158

159
      # sources deleted during this script run
160
      Builtins.foreach(@sourceStatesIn) do |one_source|
×
161
        src_id = Builtins.tointeger(Ops.get(one_source, "SrcId"))
×
162
        deleted_repos = Builtins.add(deleted_repos, src_id) if !src_id.nil?
×
163
      end
164

165
      # sources is a copy of sourceStatesOut
166
      Builtins.foreach(@sourceStatesOut) do |one_source|
×
167
        src_id = Builtins.tointeger(Ops.get(one_source, "SrcId"))
×
168
        if Builtins.contains(current_sources, src_id)
×
169
          known_repos = Builtins.add(known_repos, src_id) if !src_id.nil?
×
170
          ret = Builtins.add(ret, one_source)
×
171
        else
172
          Builtins.y2milestone("Source %1 has been removed already", one_source)
×
173
        end
174
      end
175

176
      Builtins.foreach(current_sources) do |one_srcid|
×
177
        # already known repository
178
        next if Builtins.contains(known_repos, one_srcid)
×
179
        # already deleted repository
180
        next if Builtins.contains(deleted_repos, one_srcid)
×
181
        # already deleted repository
182
        next if Builtins.contains(SourceManager.just_removed_sources, one_srcid)
×
183

184
        # repository has been added recently (by some external functionality
185
        # that doesn't use these internal variables)
186
        generalData = Pkg.SourceGeneralData(one_srcid)
×
187
        Ops.set(generalData, "enabled", true)
×
188
        Ops.set(generalData, "SrcId", one_srcid)
×
189
        Builtins.y2milestone("New repository found: %1", generalData)
×
190
        ret = Builtins.add(ret, generalData)
×
191
      end
192

193
      @sourceStatesOut = deep_copy(ret)
×
194

195
      nil
196
    end
197

198
    def PriorityToString(priority)
1✔
199
      ret = Builtins.tostring(priority)
×
200

201
      # pad to 3 characters
202
      rest = Ops.subtract(3, Builtins.size(ret))
×
203
      while Ops.greater_than(rest, 0)
×
204
        ret = Ops.add(" ", ret)
×
205
        rest = Ops.subtract(rest, 1)
×
206
      end
207

208
      ret += " (" + _("Default") + ")" if priority == @default_priority
×
209

210
      ret
×
211
    end
212

213
    def ReposFromService(service, input)
1✔
214
      input = deep_copy(input)
×
215
      service = "" if service == NO_SERVICE
×
216
      Builtins.filter(input) do |repo|
×
217
        Ops.get_string(repo, "service", "") == service
×
218
      end
219
    end
220

221
    #     Create a table item from a map as returned by the InstSrcManager agent.
222
    #     @param [Hash] source The map describing the source as returned form the agent.
223
    #     @return An item suitable for addition to a Table.
224
    def createItem(index, source, repository_mode)
1✔
225
      source = deep_copy(source)
×
226
      id = Ops.get_integer(source, "SrcId", 0)
×
227
      generalData = Pkg.SourceGeneralData(id)
×
228
      Builtins.y2milestone("generalData(%1): %2", id, generalData)
×
229

230
      name = if repository_mode
×
231
        if Builtins.haskey(source, "name")
×
232
          Ops.get_string(source, "name", "")
×
233
        else
234
          Ops.get_locale(
×
235
            # unkown name (alias) of the source
236
            generalData,
237
            "alias",
238
            Ops.get_locale(generalData, "type", _("Unknown Name"))
239
          )
240
        end
241
      else
242
        Ops.get_string(source, "name", "")
×
243
      end
244

245
      priority = Ops.get_integer(source, "priority", @default_priority)
×
246
      url = if repository_mode
×
247
        Ops.get_string(generalData, "url", "")
×
248
      else
249
        Ops.get_string(source, "url", "")
×
250
      end
251
      if ![nil, "", "/"].include?(generalData["product_dir"])
×
252
        url += " (#{generalData["product_dir"]})"
×
253
      end
254
      service_alias = Ops.get_string(source, "service", "")
×
255
      service_name = if service_alias == ""
×
256
        ""
×
257
      else
258
        Ops.get_string(Pkg.ServiceGet(service_alias), "name", "")
×
259
      end
260

261
      item = if repository_mode
×
262
        Item(
×
263
          Id(index),
264
          PriorityToString(priority),
265
          if Ops.get_boolean(
×
266
            # corresponds to the "Enable/Disable" button
267
            source,
268
            "enabled",
269
            true
270
          )
271
            UI.Glyph(:CheckMark)
×
272
          else
273
            ""
×
274
          end,
275
          Ops.get_boolean(source, "autorefresh", true) ? UI.Glyph(:CheckMark) : "",
×
276
          # translators: unknown name for a given source
277
          name,
278
          service_name,
279
          url
280
        )
281
      else
282
        Item(
×
283
          Id(index),
284
          if Ops.get_boolean(
×
285
            # corresponds to the "Enable/Disable" button
286
            source,
287
            "enabled",
288
            true
289
          )
290
            UI.Glyph(:CheckMark)
×
291
          else
292
            ""
×
293
          end,
294
          Ops.get_boolean(source, "autorefresh", true) ? UI.Glyph(:CheckMark) : "",
×
295
          # translators: unknown name for a given source
296
          name,
297
          url
298
        )
299
      end
300

301
      deep_copy(item)
×
302
    end
303

304
    def getSourceInfo(_index, source)
1✔
305
      source = deep_copy(source)
×
306
      id = Ops.get_integer(source, "SrcId", 0)
×
307
      generalData = Pkg.SourceGeneralData(id)
×
308
      Builtins.y2milestone("generalData(%1): %2", id, generalData)
×
309

310
      # get the editable propertis from 'source' parameter,
311
      # get the fixed propertis from the package manager
312
      out = {
×
313
        "enabled"      => Ops.get_boolean(source, "enabled", true),
314
        "autorefresh"  => Ops.get_boolean(source, "autorefresh", true),
315
        "name"         => Ops.get_locale(source, "name", _("Unknown Name")),
316
        "raw_name"     => source.fetch("raw_name", _("Unknown Name")),
317
        "url"          => Ops.get_string(generalData, "url", ""),
318
        "raw_url"      => Ops.get_string(generalData, "raw_url", ""),
319
        "type"         => Ops.get_string(generalData, "type", ""),
320
        "priority"     => Ops.get_integer(source, "priority", @default_priority),
321
        "service"      => Ops.get_string(source, "service", ""),
322
        "keeppackages" => Ops.get_boolean(source, "keeppackages", false)
323
      }
324
      deep_copy(out)
×
325
    end
326

327
    # Fill sources table with entries from the InstSrcManager agent.
328
    def fillTable(repo_mode, service_name)
1✔
329
      Builtins.y2milestone(
×
330
        "Filling repository table: repository mode: %1, service: %2",
331
        repo_mode,
332
        service_name
333
      )
334
      items = []
×
335

336
      if repo_mode
×
337
        # because Online Repositories / Community Repositories don't use
338
        # these internal data maps
339
        RemoveDeletedAddNewRepos()
×
340
      end
341

342
      itemList = repo_mode ? deep_copy(@sourceStatesOut) : deep_copy(@serviceStatesOut)
×
343

344
      # display only repositories from the selected service
345
      itemList = ReposFromService(service_name, itemList) if repo_mode && service_name != ""
×
346

347
      numItems = Builtins.size(itemList)
×
348

349
      i = 0
×
350
      while Ops.less_than(i, numItems)
×
351
        items = Builtins.add(
×
352
          items,
353
          createItem(i, Ops.get(itemList, i, {}), repo_mode)
354
        )
355
        i = Ops.add(i, 1)
×
356
      end
357

358
      Builtins.y2milestone("New table content: %1", items)
×
359

360
      UI.ChangeWidget(Id(:table), :Items, items)
×
361

362
      nil
363
    end
364

365
    def repoInfoRichText(name, category, info)
1✔
366
      raw_name = info["raw_name"]
×
367

368
      url = info["url"]
×
369
      raw_url = info["raw_url"]
×
370

371
      schema = Builtins.tolower(
×
372
        Ops.get_string(URL.Parse(url), "scheme", "")
373
      )
374
      icon = ["cd", "dvd", "iso"].include?(schema) ? "yast-cd_update" : "yast-http-server"
×
375
      icon_tag = "<IMG HEIGHT=\"22\" SRC=\"#{icon}\">&nbsp;&nbsp;&nbsp;"
×
376

377
      # TRANSLATORS: the raw name is the original repository name with unexpanded variables
378
      # like "$releasever"
379
      name_string = (name != raw_name) ? (_("Raw name: %s") % raw_name) + "<BR>" : ""
×
380

381
      url = _("Unknown") if url == ""
×
382
      raw_url = _("Unknown") if raw_url == ""
×
383

384
      url_string = Builtins.sformat(_("URL: %1"), url)
×
385
      if url != raw_url
×
386
        url_string += "<BR>"
×
387
        # TRANSLATORS: Raw URL is the address without expanding repo variables
388
        # e.g. Raw URL = http://something/$arch -> URL = http://something/x86_64
389
        url_string += _("Raw URL: %s") % raw_url
×
390
      end
391

392
      Builtins.sformat(
×
393
        "<P>%1<B><BIG>%2</BIG></B></P><P>%3%4<BR>%5</P>",
394
        icon_tag,
395
        name,
396
        name_string,
397
        url_string,
398
        category
399
      )
400
    end
401

402
    def repoInfoTerm
1✔
403
      if textmode
×
404
        VBox(
×
405
          Left(Heading(Id(:name), Opt(:hstretch), "")),
406
          Left(Label(Id(:url), Opt(:hstretch), "")),
407
          Left(Label(Id(:category), Opt(:hstretch), ""))
408
        )
409
      else
410
        VSquash(MinHeight(4, RichText(Id(:repo_info), "")))
×
411
      end
412
    end
413

414
    def fillRepoInfo(index, source, repo_mode, _service_name)
1✔
415
      source = deep_copy(source)
×
416
      info = repo_mode ? getSourceInfo(index, source) : deep_copy(source)
×
417
      Builtins.y2milestone("getSourceInfo(%1, %2): %3", index, source, info) if repo_mode
×
418

419
      # heading - in case repo name not found
420
      name = Ops.get_locale(info, "name", _("Unknown Repository Name"))
×
421

422
      # label to be used instead of URL if not found
423
      url = Builtins.sformat(
×
424
        _("URL: %1"),
425
        Ops.get_locale(info, "url", _("Unknown"))
426
      )
427

428
      # label, %1 is repo category (eg. YUM)
429
      category = Builtins.sformat(
×
430
        _("Category: %1"),
431
        Ops.get_locale(info, "type", _("Unknown"))
432
      )
433

434
      # don't display category for services
435
      category = "" if !repo_mode
×
436

437
      if textmode
×
438
        UI.ChangeWidget(Id(:name), :Label, name)
×
439
        UI.ChangeWidget(Id(:url), :Label, url)
×
440
        UI.ChangeWidget(Id(:category), :Label, category)
×
441
      else
442
        UI.ChangeWidget(
×
443
          Id(:repo_info),
444
          :Value,
445
          repoInfoRichText(name, category, info)
446
        )
447
      end
448

449
      UI.ChangeWidget(
×
450
        Id(:enable),
451
        :Value,
452
        Ops.get_boolean(info, "enabled", true)
453
      )
454
      UI.ChangeWidget(
×
455
        Id(:autorefresh),
456
        :Value,
457
        Ops.get_boolean(info, "autorefresh", true)
458
      )
459

460
      if repo_mode
×
461
        # priority and keeppackages are displayed only for repositories
462
        UI.ChangeWidget(
×
463
          Id(:priority),
464
          :Value,
465
          Ops.get_integer(info, "priority", @default_priority)
466
        )
467
        UI.ChangeWidget(
×
468
          Id(:keeppackages),
469
          :Value,
470
          Ops.get_boolean(info, "keeppackages", false)
471
        )
472
      end
473

474
      nil
475
    end
476

477
    def clearRepoInfo
1✔
478
      if textmode
×
479
        UI.ChangeWidget(Id(:name), :Label, "")
×
480
        UI.ChangeWidget(Id(:url), :Label, "")
×
481
        UI.ChangeWidget(Id(:category), :Label, "")
×
482
      else
483
        UI.ChangeWidget(Id(:repo_info), :Value, "")
×
484
      end
485

486
      UI.ChangeWidget(Id(:enable), :Value, false)
×
487
      UI.ChangeWidget(Id(:autorefresh), :Value, false)
×
488

489
      if UI.WidgetExists(Id(:priority))
×
490
        # priority is displayed only for repositories
491
        UI.ChangeWidget(Id(:priority), :Value, @default_priority)
×
492
      end
493

494
      nil
495
    end
496

497
    def fillCurrentRepoInfo
1✔
498
      selected = Convert.to_integer(UI.QueryWidget(Id(:table), :CurrentItem))
×
499
      if selected.nil?
×
500
        clearRepoInfo
×
501
        return
×
502
      end
503

504
      data = if @repository_view
×
505
        if @displayed_service == ""
×
506
          Ops.get(@sourceStatesOut, selected, {})
×
507
        else
508
          Ops.get(
×
509
            ReposFromService(@displayed_service, @sourceStatesOut),
510
            selected,
511
            {}
512
          )
513
        end
514
      else
515
        Ops.get(@serviceStatesOut, selected, {})
×
516
      end
517

518
      fillRepoInfo(selected, data, @repository_view, @displayed_service)
×
519

520
      nil
521
    end
522

523
    # Find which repositories have to be added or deleted to ZENworks.
524
    # #182992: formerly we did not consider the enabled attribute.
525
    # But ZENworks cannot completely disable a repository (unsubscribing a
526
    # repository merely decreases its priority) so we consider a disabled repository
527
    # like a deleted one.
528
    # @param [Array<Hash{String => Object>}] states_old sourceStates - In or Out
529
    # @param [Array<Hash{String => Object>}] states_new sourceStates - In or Out
530
    # @return the list of SrcId's that are enabled in statesNew
531
    #  but are not enabled in states_old
532
    def newSources(states_old, states_new)
1✔
533
      states_old = deep_copy(states_old)
×
534
      states_new = deep_copy(states_new)
×
535
      Builtins.y2milestone("From %1 To %2", states_old, states_new)
×
536
      ret = []
×
537
      seen = Builtins.listmap(states_old) do |src|
×
538
        {
×
539
          Ops.get_integer(src, "SrcId", -1) => Ops.get_boolean(
540
            src,
541
            "enabled",
542
            true
543
          )
544
        }
545
      end
546
      Builtins.foreach(states_new) do |src|
×
547
        newid = Ops.get_integer(src, "SrcId", -1)
×
548
        newena = Ops.get_boolean(src, "enabled", true)
×
549
        ret = Builtins.add(ret, newid) if newena && !Ops.get(seen, newid, false)
×
550
      end
551
      Builtins.y2milestone("Difference %1", ret)
×
552
      deep_copy(ret)
×
553
    end
554

555
    def newServices(states_old, states_new)
1✔
556
      states_old = deep_copy(states_old)
×
557
      states_new = deep_copy(states_new)
×
558
      Builtins.y2milestone("Services from %1 To %2", states_old, states_new)
×
559
      ret = []
×
560

561
      seen = Builtins.maplist(states_old) do |srv|
×
562
        Ops.get_string(srv, "alias", "")
×
563
      end
564

565
      Builtins.foreach(states_new) do |srv|
×
566
        alias_name = Ops.get_string(srv, "alias", "")
×
567
        Builtins.y2milestone("Checking %1", alias_name)
×
568
        ret = Builtins.add(ret, alias_name) if !Builtins.contains(seen, alias_name)
×
569
      end
570
      Builtins.y2milestone("Difference %1", ret)
×
571
      deep_copy(ret)
×
572
    end
573

574
    def deleteSource(index)
1✔
575
      srcid = Ops.get_integer(@sourceStatesOut, [index, "SrcId"], -1)
×
576

577
      if srcid != -1
×
578
        @sourcesToDelete = Builtins.add(@sourcesToDelete, srcid)
×
579
        SourceManager.just_removed_sources = Builtins.add(
×
580
          SourceManager.just_removed_sources,
581
          srcid
582
        )
583
      end
584

585
      @sourceStatesOut = Builtins.remove(@sourceStatesOut, index)
×
586

587
      nil
588
    end
589

590
    def deleteService(index)
1✔
591
      Builtins.y2milestone("Removing service: %1", index)
×
592
      @serviceStatesOut = Builtins.remove(@serviceStatesOut, index)
×
593

594
      nil
595
    end
596

597
    def Write
1✔
598
      success = true
×
599

600
      # evaluate removed and new services
601
      deleted_services = newServices(@serviceStatesOut, @serviceStatesIn)
×
602
      Builtins.y2milestone("Deleted services: %1", deleted_services)
×
603
      added_services = newServices(@serviceStatesIn, @serviceStatesOut)
×
604
      Builtins.y2milestone("Added services: %1", added_services)
×
605

606
      Builtins.foreach(deleted_services) do |alias_name|
×
607
        Builtins.y2milestone("Removing service %1", alias_name)
×
608
        success &&= Pkg.ServiceDelete(alias_name)
×
609
      end
610

611
      Builtins.y2milestone("New service config: %1", @serviceStatesOut)
×
612
      Builtins.foreach(@serviceStatesOut) do |s|
×
613
        alias_name = Ops.get_string(s, "alias", "")
×
614
        if Builtins.contains(added_services, alias_name)
×
615
          Builtins.y2milestone("Adding service %1", alias_name)
×
616
          new_url = Ops.get_string(s, "url", "")
×
617

618
          if new_url == ""
×
619
            Builtins.y2error("Empty URL for service %1", alias_name)
×
620
          else
621
            Builtins.y2milestone("aliases: %1", Pkg.ServiceAliases)
×
622
            success &&= Pkg.ServiceAdd(alias_name, new_url)
×
623
            # set enabled and autorefresh flags
624
            success &&= Pkg.ServiceSet(alias_name, s)
×
625
          end
626
        else
627
          Builtins.y2milestone("Modifying service %1", alias_name)
×
628
          success &&= Pkg.ServiceSet(alias_name, s)
×
629
        end
630
      end
631

632
      # if started from the package manager we need to call these extra
633
      # pkg-bindings to sync the pool state
634
      if @full_mode
×
635
        @sourceStatesOut.each do |src|
×
636
          srcid = src["SrcId"]
×
637
          next unless Pkg.SourceGetCurrent(false).include?(srcid)
×
638

639
          Pkg.SourceSetEnabled(srcid, src["enabled"])
×
640
          Pkg.SourceSetPriority(srcid, src["priority"])
×
641
        end
642
      end
643

644
      Builtins.y2milestone("New repo config: %1", @sourceStatesOut)
×
645
      success &&= Pkg.SourceEditSet(@sourceStatesOut)
×
646

647
      # we must sync before the repositories are deleted from zypp
648
      # otherwise we will not get their details
649
      added = newSources(@sourceStatesIn, @sourceStatesOut)
×
650

651
      Builtins.foreach(@sourcesToDelete) do |id|
×
652
        if Builtins.contains(@reposFromDeletedServices, id)
×
653
          Builtins.y2milestone(
×
654
            "Repository %1 has been already removed (belongs to a deleted service)",
655
            id
656
          )
657
        else
658
          success &&= Pkg.SourceDelete(id)
×
659
        end
660
      end
661

662
      refresh_enabled = Builtins.contains(WFM.Args, "refresh-enabled")
×
663

664
      Builtins.foreach(@sourceStatesOut) do |src_state|
×
665
        srcid = Ops.get_integer(src_state, "SrcId", -1)
×
666
        if refresh_enabled && Builtins.contains(added, srcid)
×
667
          Builtins.y2milestone("Refreshing enabled repository: %1", srcid)
×
668
          Ops.set(src_state, "do_refresh", true)
×
669
        end
670
        if Ops.get_boolean(src_state, "do_refresh", false)
×
671
          Builtins.y2milestone("Downloading metadata for source %1", srcid)
×
672

673
          success &&= Pkg.SourceRefreshNow(srcid)
×
674
        end
675
      end
676

677
      success &&= KeyManager.Write
×
678

679
      # store repositories and services in the persistent libzypp storage
680
      success &&= Pkg.SourceSaveAll # #176013
×
681

682
      success
×
683
    end
684

685
    def buildList
1✔
686
      ret = [
×
687
        Item(Id(:all_repositories), _("All repositories"), @repository_view),
688
        Item(
689
          Id(:all_services),
690
          _("All services"),
691
          !@repository_view && @displayed_service == ""
692
        )
693
      ]
694

695
      Builtins.foreach(@serviceStatesOut) do |srv_state|
×
696
        t = Item(
×
697
          Id(Ops.get_string(srv_state, "alias", "")),
698
          Builtins.sformat(
699
            _("Service '%1'"),
700
            Ops.get_string(srv_state, "name", "")
701
          ),
702
          @repository_view &&
703
            @displayed_service == Ops.get_string(srv_state, "alias", "")
704
        )
705
        ret = Builtins.add(ret, t)
×
706
      end
707

708
      # there is some service, so allow to filter repos without service (bnc#944504)
709
      if ret.size > 2
×
710
        t = Item(
×
711
          Id(NO_SERVICE_ITEM),
712
          # TRANSLATORS: Item in selection box that allow user to see only
713
          # repositories not associated with service. Sometimes called also
714
          # third party as they are usually repositories not provided by SUSE
715
          # within product subscription.
716
          _("Only repositories not provided by a service"),
717
          @repository_view &&
718
            @displayed_service == NO_SERVICE
719
        )
720
        ret = Builtins.add(ret, t)
×
721
      end
722

723
      ret
×
724
    end
725

726
    def RepoFilterWidget
1✔
727
      # combobox label
728
      ComboBox(Id(:service_filter), Opt(:notify), _("View"), buildList)
×
729
    end
730

731
    def UpdateCombobox
1✔
732
      UI.ReplaceWidget(Id(:filter_rp), RepoFilterWidget())
×
733

734
      nil
735
    end
736

737
    # return table widget definition
738
    # layout of the table depends on the current mode (services do not have priorities)
739
    def TableWidget(repository_mode)
1✔
740
      tabheader = if repository_mode
×
741
        Header(
×
742
          # table header - priority of the repository - keep the translation as short as possible!
743
          _("Priority"),
744
          # table header - is the repo enabled? - keep the translation as short as possible!
745
          Center(_("Enabled")),
746
          # table header - is autorefresh enabled for the repo?
747
          # keep the translation as short as possible!
748
          Center(_("Autorefresh")),
749
          # table header - name of the repo
750
          _("Name"),
751
          # table header - service to which the repo belongs
752
          _("Service"),
753
          # table header - URL of the repo
754
          _("URL")
755
        )
756
      else
757
        Header(
×
758
          # table header - is the repo enabled? - keep the translation as short as possible!
759
          Center(_("Enabled")),
760
          # table header - is autorefresh enabled for the repo?
761
          # keep the translation as short as possible!
762
          Center(_("Autorefresh")),
763
          # table header - name of the repo
764
          _("Name"),
765
          # table header - URL of the repo
766
          _("URL")
767
        )
768
      end
769

770
      Table(Id(:table), Opt(:notify, :immediate), tabheader, [])
×
771
    end
772

773
    def ReplaceWidgets(repo_mode)
1✔
774
      Builtins.y2milestone("Replacing the table widget")
×
775
      UI.ReplaceWidget(Id(:tabrp), TableWidget(repo_mode))
×
776

777
      UI.ReplaceWidget(
×
778
        Id(:priorp),
779
        if repo_mode
×
780
          IntField(
×
781
            Id(:priority),
782
            Opt(:notify),
783
            @priority_label,
784
            0,
785
            200,
786
            @default_priority
787
          )
788
        else
789
          Empty()
×
790
        end
791
      )
792
      UI.ReplaceWidget(
×
793
        Id(:keeppkg_rp),
794
        if repo_mode
×
795
          CheckBox(Id(:keeppackages), Opt(:notify), @keeppackages_label)
×
796
        else
797
          Empty()
×
798
        end
799
      )
800

801
      nil
802
    end
803

804
    def RemoveReposFromService(service_alias)
1✔
805
      # delete the repositories belonging to the service
806
      repos = ReposFromService(service_alias, @sourceStatesOut)
×
807
      Builtins.y2milestone(
×
808
        "Removing repos from service alias=%1: %2",
809
        service_alias,
810
        repos
811
      )
812

813
      Builtins.foreach(repos) do |repo|
×
814
        srcid = Ops.get_integer(repo, "SrcId", -1)
×
815
        if srcid != -1
×
816
          @sourcesToDelete = Builtins.add(@sourcesToDelete, srcid)
×
817
          SourceManager.just_removed_sources = Builtins.add(
×
818
            SourceManager.just_removed_sources,
819
            srcid
820
          )
821
        end
822
        @sourceStatesOut = Builtins.filter(@sourceStatesOut) do |srcstate|
×
823
          if Ops.get_integer(srcstate, "SrcId", -1) == srcid
×
824
            Builtins.y2milestone("Removing repository %1", srcstate)
×
825
            @reposFromDeletedServices = Builtins.add(
×
826
              @reposFromDeletedServices,
827
              srcid
828
            )
829
            next false
×
830
          end
831
          true
×
832
        end
833
      end
834

835
      nil
836
    end
837

838
    def SetReposStatusFromService(service_alias, enable)
1✔
839
      # delete the repositories belonging to the service
840
      repos = ReposFromService(service_alias, @sourceStatesOut)
×
841
      Builtins.y2milestone(
×
842
        "%1 repos from service alias=%2: %3",
843
        enable ? "Enabling" : "Disabling",
×
844
        service_alias,
845
        repos
846
      )
847

848
      Builtins.foreach(repos) do |repo|
×
849
        srcid = Ops.get_integer(repo, "SrcId", -1)
×
850
        @sourceStatesOut = Builtins.maplist(@sourceStatesOut) do |srcstate|
×
851
          if Ops.get_integer(srcstate, "SrcId", -1) == srcid
×
852
            Builtins.y2milestone(
×
853
              "%1 repository %2",
854
              enable ? "Enabling" : "Disabling",
×
855
              srcstate
856
            )
857
            Ops.set(srcstate, "enabled", enable)
×
858
          end
859
          deep_copy(srcstate)
×
860
        end
861
      end
862

863
      nil
864
    end
865

866
    def SummaryDialog
1✔
867
      Builtins.y2milestone("Running Summary dialog")
×
868

869
      # push button - refresh the selected repository now
870
      refreshButtonLabel = _("Re&fresh Selected")
×
871

872
      contents = VBox(
×
873
        Right(ReplacePoint(Id(:filter_rp), RepoFilterWidget())),
874
        VWeight(1, ReplacePoint(Id(:tabrp), TableWidget(@repository_view))),
875
        repoInfoTerm,
876
        # label
877
        Left(Label(_("Properties"))),
878
        HBox(
879
          HSquash(
880
            VBox(
881
              # check box
882
              Left(CheckBox(Id(:enable), Opt(:notify), _("&Enabled"))),
883
              # check box
884
              Left(
885
                CheckBox(
886
                  Id(:autorefresh),
887
                  Opt(:notify),
888
                  _("Automatically &Refresh")
889
                )
890
              )
891
            )
892
          ),
893
          HSpacing(1),
894
          HSquash(
895
            Bottom(
896
              # check box
897
              ReplacePoint(
898
                Id(:keeppkg_rp),
899
                CheckBox(Id(:keeppackages), Opt(:notify), @keeppackages_label)
900
              )
901
            )
902
          ),
903
          HSpacing(1),
904
          HSquash(
905
            ReplacePoint(
906
              Id(:priorp),
907
              IntField(
908
                Id(:priority),
909
                Opt(:notify),
910
                @priority_label,
911
                0,
912
                200,
913
                @default_priority
914
              )
915
            )
916
          ),
917
          HStretch()
918
        ),
919
        VSpacing(0.4),
920
        HBox(
921
          PushButton(Id(:add), Opt(:key_F3), Label.AddButton),
922
          PushButton(Id(:replace), Opt(:key_F4), Label.EditButton),
923
          PushButton(Id(:delete), Opt(:key_F5), Label.DeleteButton),
924
          HStretch(),
925
          # push button label
926
          PushButton(Id(:key_mgr), _("&GPG Keys...")),
927
          # menu button label
928
          MenuButton(
929
            Id(:menu_button),
930
            Opt(:key_F6),
931
            _("Refresh"),
932
            [
933
              Item(Id(:refresh), refreshButtonLabel),
934
              # menu button label
935
              Item(Id(:autorefresh_all), _("Refresh all Autor&efreshed")),
936
              # menu button label
937
              Item(Id(:refresh_enabled), _("Refresh all &Enabled"))
938
            ]
939
          )
940
        )
941
      )
942

943
      # dialog caption
944
      title = _("Configured Software Repositories")
×
945

946
      # help
947
      help_text = _(
×
948
        "<p>\nManage configured software repositories and services.</p>\n"
949
      )
950

951
      help_text = Ops.add(
×
952
        help_text,
953
        _(
954
          "<P>A <B>service</B> or <B>Repository Index Service (RIS) </B> is a protocol for " \
955
          "package repository management. A service can offer one or more software " \
956
          "repositories which can be dynamically changed by the service administrator.</P>"
957
        )
958
      )
959

960
      help_text = Ops.add(
×
961
        help_text,
962
        _(
963
          "<p>\n" \
964
          "<b>Adding a new Repository or a Service</b><br>\n" \
965
          "To add a new repository, use <b>Add</b> and specify the software repository or " \
966
          "service.\n YaST will automatically detect whether a service or a repository is " \
967
          "available at the entered location.\n</p>\n"
968
        )
969
      )
970

971
      # help, continued
972
      help_text = Ops.add(
×
973
        help_text,
974
        _(
975
          "<p>\n" \
976
          "To install packages from <b>CD</b>,\n" \
977
          "have the CD set or the DVD available.\n" \
978
          "</p>\n"
979
        )
980
      )
981

982
      # help, continued
983
      help_text = Ops.add(
×
984
        help_text,
985
        _(
986
          "<p>\n" \
987
          "The CDs can be copied to <b>hard disk</b>\n" \
988
          "and then used as a repository.\n" \
989
          "Insert the path name where the first\n" \
990
          "CD is located, for example, /data1/<b>CD1</b>.\n" \
991
          "Only the base path is required if all CDs are copied\n" \
992
          "into one directory.\n" \
993
          "</p>\n"
994
        )
995
      )
996

997
      # help, continued
998
      help_text = Ops.add(
×
999
        help_text,
1000
        _(
1001
          "<p>\n" \
1002
          "<b>Modifying Status of a Repository or a Service</b><br>\n" \
1003
          "To change a repository location, use <b>Edit</b>. To remove a repository, use\n" \
1004
          "<b>Delete</b>. To enable or disable the repository or to change the refresh status " \
1005
          "at initialization time, select the repository in the table and use the check boxes " \
1006
          "below.\n</p>\n"
1007
        )
1008
      )
1009

1010
      # help text, continued
1011
      help_text = Ops.add(
×
1012
        help_text,
1013
        _(
1014
          "<P><B>Priority of a Repository</B><BR>\nPriority of a repository is " \
1015
          "an integer value between 0 (the highest priority) and 200 (the lowest priority). " \
1016
          "Default is 99. If a package is available in more repositories, " \
1017
          "the repository with the highest priority is used.</P>\n"
1018
        )
1019
      )
1020

1021
      # help text, continued
1022
      help_text = Ops.add(
×
1023
        help_text,
1024
        _(
1025
          "<P>Select the appropriate option on top of the window for navigation in " \
1026
          "repositories and services.</P>"
1027
        )
1028
      )
1029
      # help text, continued
1030
      help_text = Ops.add(
×
1031
        Ops.add(
1032
          help_text,
1033
          _(
1034
            "<P><B>Keep Downloaded Packages</B><BR>Check this option to keep downloaded\n" \
1035
            "packages in a local cache so they can be reused later when the packages are\n" \
1036
            "reinstalled. If not checked, the downloaded packages are deleted after " \
1037
            "installation.</P>"
1038
          )
1039
        ),
1040
        _(
1041
          "<P>The default local cache is located in directory <B>/var/cache/zypp/packages</B>. " \
1042
          "Change the location in <B>/etc/zypp/zypp.conf</B> file.</P>"
1043
        )
1044
      )
1045

1046
      Wizard.SetNextButton(:next, Label.OKButton)
×
1047
      Wizard.SetAbortButton(:abort, Label.CancelButton)
×
1048

1049
      Wizard.SetContents(title, contents, help_text, false, true)
×
1050
      Wizard.HideBackButton
×
1051

1052
      fillTable(@repository_view, @displayed_service)
×
1053
      fillCurrentRepoInfo
×
1054

1055
      input = nil
×
1056

1057
      current = -1
×
1058

1059
      exit = false
×
1060
      begin
1061
        if !current.nil? && Ops.greater_or_equal(current, 0)
×
1062
          UI.ChangeWidget(Id(:table), :CurrentItem, current)
×
1063
          fillCurrentRepoInfo
×
1064
        end
1065

1066
        current = -1
×
1067

1068
        event = UI.WaitForEvent
×
1069
        input = Ops.get_symbol(event, "ID", :nothing)
×
1070
        Builtins.y2debug("Input: %1", input)
×
1071
        if input == :table &&
×
1072
            Ops.get_string(event, "EventReason", "") == "Activated"
1073
          input = :enable
×
1074
        end
1075

1076
        return :add if input == :add
×
1077

1078
        case input
×
1079
        when :next
1080
          # store the new state
1081
          success = Write()
×
1082
          if success
×
1083
            exit = true
×
1084
          else
1085
            # popup message part 1
1086
            message1 = _(
×
1087
              "Unable to save changes to the repository\nconfiguration."
1088
            )
1089
            details = Pkg.LastError
×
1090
            Builtins.y2milestone("LastError: %1", details)
×
1091
            # popup message part 2 followed by other info
1092
            message2 = (details != "") ? Ops.add(_("Details:") + "\n", details) : ""
×
1093
            # popup message part 3
1094
            message2 = Ops.add(Ops.add(message2, "\n"), _("Try again?"))
×
1095

1096
            tryagain = Popup.YesNo(Ops.add(Ops.add(message1, "\n"), message2))
×
1097
            exit = true if !tryagain
×
1098
          end
1099
        # Wizard::UserInput returns `back instead of `cancel when window is closed by WM
1100
        when :abort, :cancel
1101
          # handle cancel as abort
1102
          input = :abort
×
1103

1104
          # no change, do not confirm exit
1105
          if @sourceStatesOut == @sourceStatesIn
×
1106
            exit = true
×
1107
          else
1108
            # popup headline
1109
            headline = _("Abort Repository Configuration")
×
1110
            # popup message
1111
            msg = _(
×
1112
              "Abort the repository configuration?\nAll changes will be lost."
1113
            )
1114
            exit = true if Popup.YesNoHeadline(headline, msg)
×
1115
          end
1116
        when :key_mgr
1117
          exit = true
×
1118
          # return `key_mgr;
1119
          # start the GPG key manager
1120
          # RunGPGKeyMgmt();
1121
        when :service_filter
1122
          # handle the combobox events here...
1123
          current_item = UI.QueryWidget(Id(:service_filter), :Value)
×
1124

1125
          # rebuild the dialog if needed
1126
          Builtins.y2milestone("Current combobox item: %1", current_item)
×
1127
          update_table_widget = false
×
1128

1129
          if current_item == :all_repositories
×
1130
            update_table_widget = !@repository_view || @displayed_service != ""
×
1131
            Builtins.y2milestone("Switching to repository view")
×
1132
            @repository_view = true
×
1133
            @displayed_service = ""
×
1134
          elsif current_item == :all_services
×
1135
            update_table_widget = @repository_view
×
1136
            Builtins.y2milestone("Switching to service view")
×
1137
            @repository_view = false
×
1138
            # display all services
1139
            @displayed_service = ""
×
1140
          elsif current_item == NO_SERVICE_ITEM
×
1141
            update_table_widget = @repository_view
×
1142
            Builtins.y2milestone("Switching to without service view")
×
1143
            @repository_view = true
×
1144
            # display repositories without service
1145
            @displayed_service = NO_SERVICE
×
1146
          elsif Ops.is_string?(current_item)
×
1147
            # switch to the selected repository
1148
            Builtins.y2milestone("Switching to service %1", current_item)
×
1149
            @repository_view = true
×
1150
            # display the selected service
1151
            @displayed_service = Convert.to_string(current_item)
×
1152

1153
            # FIXME: always update the table?
1154
            update_table_widget = true
×
1155
          end
1156

1157
          # update table widget
1158
          ReplaceWidgets(@repository_view) if update_table_widget
×
1159

1160
          # update table content
1161
          fillTable(@repository_view, @displayed_service)
×
1162
          fillCurrentRepoInfo
×
1163

1164
          # update the current item
1165
          current = Convert.to_integer(UI.QueryWidget(Id(:table), :CurrentItem))
×
1166
        else
1167
          current = Convert.to_integer(UI.QueryWidget(Id(:table), :CurrentItem))
×
1168

1169
          Builtins.y2debug("Current item: %1", current)
×
1170

1171
          source_state = {}
×
1172

1173
          # global_current - 'current' that points to global sourceStatesOut
1174
          global_current = -1
×
1175

1176
          if @repository_view
×
1177
            if @displayed_service == ""
×
1178
              source_state = Ops.get(@sourceStatesOut, current, {})
×
1179
              global_current = current
×
1180
            elsif !current.nil?
×
1181
              sources_from_service = ReposFromService(
×
1182
                @displayed_service,
1183
                @sourceStatesOut
1184
              )
1185
              source_state = Ops.get(sources_from_service, current, {})
×
1186

1187
              Builtins.find(@sourceStatesOut) do |s|
×
1188
                global_current = Ops.add(global_current, 1)
×
1189
                Ops.get(s, "SrcId") ==
×
1190
                  Ops.get_integer(source_state, "SrcId", -1)
1191
              end
1192

1193
              Builtins.y2milestone("global_current: %1", global_current)
×
1194
            end
1195
          end
1196

1197
          id = Ops.get_integer(source_state, "SrcId", -1)
×
1198

1199
          if Ops.less_than(id, 0) && @repository_view &&
×
1200
              @displayed_service == ""
1201
            Builtins.y2error(
×
1202
              "Unable to determine repository id, broken repository?"
1203
            )
1204
            next
×
1205
          end
1206

1207
          case input
×
1208
          when :replace
1209
            if @repository_view
×
1210
              repo_replace_handler(source_state, global_current)
×
1211
            else
1212
              service_replace_handler(current)
×
1213
            end
1214
          when :refresh
1215
            if @repository_view
×
1216
              Pkg.SourceRefreshNow(id)
×
1217

1218
              if @full_mode && Ops.get_boolean(source_state, "enabled", false)
×
1219
                # force loading of the resolvables
1220
                Pkg.SourceSetEnabled(id, false)
×
1221
                Pkg.SourceSetEnabled(id, true)
×
1222
              end
1223
            else
1224
              # refresh a service
1225
              service_alias = Ops.get_string(
×
1226
                Ops.get(@serviceStatesOut, current, {}),
1227
                "alias",
1228
                ""
1229
              )
1230

1231
              Builtins.y2milestone("Refreshing service %1...", service_alias)
×
1232
              Pkg.ServiceRefresh(service_alias)
×
1233
            end
1234
          when :autorefresh_all, :refresh_enabled
1235
            Builtins.y2milestone(
×
1236
              "Refreshing all %1 %2%3...",
1237
              (input == :refresh_enabled) ? "enabled" : "autorefreshed",
×
1238
              @repository_view ? "repositories" : "services",
×
1239
              if @repository_view && @displayed_service != ""
×
1240
                Ops.add(" from service ", @displayed_service)
×
1241
              else
1242
                ""
×
1243
              end
1244
            )
1245

1246
            refresh_autorefresh_only = input == :autorefresh_all
×
1247
            to_refresh = 0
×
1248

1249
            data = if @repository_view
×
1250
              if @displayed_service == ""
×
1251
                deep_copy(@sourceStatesOut)
×
1252
              else
1253
                ReposFromService(@displayed_service, @sourceStatesOut)
×
1254
              end
1255
            else
1256
              deep_copy(@serviceStatesOut)
×
1257
            end
1258

1259
            Builtins.y2milestone("data: %1", data)
×
1260

1261
            Builtins.foreach(data) do |src_state|
×
1262
              if Ops.get_boolean(src_state, "enabled", false) &&
×
1263
                  (!refresh_autorefresh_only ||
1264
                    Ops.get_boolean(src_state, "autorefresh", false))
1265
                url2 = if @repository_view
×
1266
                  Ops.get_string(
×
1267
                    Pkg.SourceGeneralData(
1268
                      Ops.get_integer(src_state, "SrcId", -1)
1269
                    ),
1270
                    "url",
1271
                    ""
1272
                  )
1273
                else
1274
                  Ops.get_string(src_state, "url", "")
×
1275
                end
1276
                schema = Builtins.tolower(Builtins.substring(url2, 0, 3))
×
1277

1278
                # schema is substring, so that is reason why it is "cd:" and "dvd"
1279
                to_refresh += 1 if schema != "cd:" && schema != "dvd"
×
1280
              end
1281
            end
1282

1283
            Builtins.y2milestone(
×
1284
              "%1 %2 will be refreshed",
1285
              to_refresh,
1286
              @repository_view ? "repositories" : "services"
×
1287
            )
1288

1289
            if Ops.greater_than(to_refresh, 0)
×
1290
              Wizard.CreateDialog
×
1291
              # TODO: add help text
1292
              Progress.New(
×
1293
                @repository_view ? _("Refreshing Repositories") : _("Refreshing Services"),
×
1294
                "",
1295
                Ops.add(to_refresh, 1),
1296
                [
1297
                  @repository_view ? _("Refresh Repositories") : _("Refresh Services")
×
1298
                ],
1299
                [],
1300
                ""
1301
              )
1302

1303
              Builtins.foreach(data) do |src_state|
×
1304
                if Ops.get_boolean(src_state, "enabled", false) &&
×
1305
                    (!refresh_autorefresh_only ||
1306
                      Ops.get_boolean(src_state, "autorefresh", false))
1307
                  name = Ops.get_string(src_state, "name", "")
×
1308
                  if @repository_view
×
1309
                    srcid = Ops.get_integer(src_state, "SrcId", -1)
×
1310

1311
                    url2 = Ops.get_string(
×
1312
                      Pkg.SourceGeneralData(
1313
                        Ops.get_integer(src_state, "SrcId", -1)
1314
                      ),
1315
                      "url",
1316
                      ""
1317
                    )
1318
                    schema = Builtins.tolower(Builtins.substring(url2, 0, 3))
×
1319

1320
                    if schema != "cd:" && schema != "dvd"
×
1321
                      Builtins.y2milestone(
×
1322
                        "Autorefreshing repository %1 (%2)",
1323
                        srcid,
1324
                        name
1325
                      )
1326

1327
                      # progress bar label
1328
                      Progress.Title(
×
1329
                        Builtins.sformat(_("Refreshing Repository %1..."), name)
1330
                      )
1331

1332
                      Pkg.SourceRefreshNow(srcid)
×
1333

1334
                      if @full_mode &&
×
1335
                          Ops.get_boolean(src_state, "enabled", false)
1336
                        # force loading of the resolvables
1337
                        Pkg.SourceSetEnabled(srcid, false)
×
1338
                        Pkg.SourceSetEnabled(srcid, true)
×
1339
                      end
1340

1341
                      Progress.NextStep
×
1342
                    else
1343
                      Builtins.y2milestone(
×
1344
                        "Skipping a CD/DVD repository %1 (%2)",
1345
                        srcid,
1346
                        name
1347
                      )
1348
                    end
1349
                  else
1350
                    service_alias = Ops.get_string(src_state, "alias", "")
×
1351

1352
                    # refreshing services
1353
                    # progress bar label
1354
                    Progress.Title(
×
1355
                      Builtins.sformat(_("Refreshing Service %1..."), name)
1356
                    )
1357
                    Builtins.y2milestone(
×
1358
                      "Refreshing service %1 (alias: %2)...",
1359
                      name,
1360
                      service_alias
1361
                    )
1362
                    Pkg.ServiceRefresh(service_alias)
×
1363
                  end
1364
                end
1365
              end
1366

1367
              Progress.Finish
×
1368
              Wizard.CloseDialog
×
1369
            end
1370
          when :delete
1371
            if @repository_view
×
1372
              repo_delete_handler(global_current)
×
1373
            else
1374
              service_delete_handler(current)
×
1375
            end
1376
          when :enable
1377
            if @repository_view
×
1378
              repo_enable_handler(source_state, global_current, current)
×
1379
            else
1380
              service_enable_handler(current)
×
1381
            end
1382
          when :autorefresh
1383
            if @repository_view
×
1384
              repo_autorefresh_handler(source_state, global_current, current)
×
1385
            else
1386
              service_autorefresh_handler(current)
×
1387
            end
1388
          when :priority
1389
            if @repository_view
×
1390
              repo_priority_handler(source_state, global_current, current)
×
1391
            else
1392
              Builtins.y2error(
×
1393
                "Ignoring event `priority: the widget should NOT be displayed in service mode!"
1394
              )
1395
            end
1396
          when :keeppackages
1397
            if @repository_view
×
1398
              repo_keeppackages_handler(source_state, global_current)
×
1399
            else
1400
              Builtins.y2error(
×
1401
                "Ignoring event `keeppackages: the widget should NOT be displayed in service mode!"
1402
              )
1403
            end
1404
          when :table
1405
            Builtins.y2warning("Unknown user input: %1", input)
×
1406
          end
1407
        end
1408
      end until exit
×
1409

1410
      Builtins.y2debug("Return: %1", input)
×
1411

1412
      input
×
1413
    end
1414

1415
    def SortReposByPriority(repos)
1✔
1416
      # check the input
1417
      return nil unless repos
3✔
1418

1419
      # sort the maps by "repos" key (in ascending order) and if same use name (bsc#957372)
1420
      ret = repos.sort_by { |r| [r.fetch("priority", @default_priority), r["name"]] }
10✔
1421

1422
      Builtins.y2milestone("SortReposByPriority: %1 -> %2", repos, ret)
2✔
1423

1424
      deep_copy(ret)
2✔
1425
    end
1426

1427
    def StartTypeDialog
1✔
1428
      seturl = @selected_url_scheme
×
1429

1430
      seturl = Ops.add(@selected_url_scheme, "://") if !seturl.nil? && seturl != ""
×
1431

1432
      ret = TypeDialogOpts(true, seturl)
×
1433

1434
      if ret == :back
×
1435
        @selected_url_scheme = ""
×
1436
      else
1437
        @selected_url_scheme = Ops.get_string(
×
1438
          URL.Parse(SourceDialogs.GetRawURL),
1439
          "scheme",
1440
          ""
1441
        )
1442
        Builtins.y2milestone("Selected URL scheme: %1", @selected_url_scheme)
×
1443

1444
        @selected_url_scheme = "url" if @selected_url_scheme.nil? || @selected_url_scheme == ""
×
1445
      end
1446

1447
      ret
×
1448
    end
1449

1450
    def url_occupied?(url)
1✔
1451
      scheme = Builtins.tolower(Ops.get_string(URL.Parse(url), "scheme", ""))
5✔
1452

1453
      # alway create CD/DVD repository
1454
      return false if optical?(scheme)
5✔
1455

1456
      ret = false
3✔
1457

1458
      Builtins.foreach(@sourceStatesOut) do |src|
3✔
1459
        src_id = Builtins.tointeger(Ops.get(src, "SrcId"))
2✔
1460
        generalData = Pkg.SourceGeneralData(src_id)
2✔
1461
        src_url = Ops.get_string(generalData, "url", "")
2✔
1462
        multi_modules = ![nil, "", "/"].include?(generalData["product_dir"])
2✔
1463
        # for multi modules single url can be used for multi repositories, so
1464
        # so it is not occupied
1465
        if (src_url == url) && !multi_modules
2✔
1466
          ret = true
1✔
1467
          break
1✔
1468
        end
1469
      end
1470

1471
      Builtins.y2milestone("URL exists: %1", ret)
3✔
1472

1473
      ret
3✔
1474
    end
1475

1476
    def StartEditDialog
1✔
1477
      Builtins.y2milestone("Edit URL with protocol %1", @selected_url_scheme)
×
1478
      ret = nil
×
1479
      begin
1480
        ret = SourceDialogs.EditDialogProtocol(@selected_url_scheme)
×
1481

1482
        if ret == :next
×
1483
          url = SourceDialogs.GetURL
×
1484
          occupied = url_occupied?(url)
×
1485

1486
          if occupied && !Popup.AnyQuestion(
×
1487
            "",
1488
            Builtins.sformat(
1489
              _(
1490
                "Repository %1\n" \
1491
                "has been already added. Each repository should be added only once.\n" \
1492
                "\n" \
1493
                "Really add the repository again?"
1494
              ),
1495
              URL.HidePassword(url)
1496
            ),
1497
            Label.YesButton,
1498
            Label.NoButton,
1499
            :focus_no
1500
          )
1501
            # ask again
1502
            ret = nil
×
1503
          end
1504
        end
1505
      end while ret.nil?
×
1506

1507
      Builtins.y2milestone("Result: %1", ret)
×
1508

1509
      ret
×
1510
    end
1511

1512
    def StartStoreSource
1✔
1513
      ret = StoreSource()
×
1514

1515
      if [:next, :abort, :close].include?(ret)
×
1516
        Builtins.y2milestone("Resetting selected URL scheme")
×
1517
        @selected_url_scheme = ""
×
1518
      end
1519

1520
      ret
×
1521
    end
1522

1523
    # main function - start the workflow
1524
    def StartInstSource
1✔
1525
      Wizard.CreateDialog
×
1526
      Wizard.SetDesktopIcon("org.opensuse.yast.SWSource")
×
1527

1528
      if !@full_mode
×
1529
        # dialog caption
1530
        Wizard.SetContents(_("Initializing..."), Empty(), "", false, true)
×
1531
        Pkg.TargetInit(Installation.destdir, true)
×
1532
      end
1533

1534
      Wizard.SetDesktopTitleAndIcon("org.opensuse.yast.SWSource")
×
1535

1536
      # check whether running as root
1537
      if !Confirm.MustBeRoot ||
×
1538
          !Ops.get_boolean(PackageLock.Connect(false), "connected", false)
1539
        UI.CloseDialog
×
1540
        return :abort
×
1541
      end
1542

1543
      PackageCallbacks.InitPackageCallbacks if !@full_mode
×
1544

1545
      # read repositories & services
1546
      restore = @full_mode ? true : Pkg.SourceRestore
×
1547

1548
      Builtins.y2milestone("Known services: %1", Pkg.ServiceAliases)
×
1549

1550
      if !restore
×
1551
        cont = Popup.AnyQuestionRichText(
×
1552
          Label.ErrorMsg,
1553
          Ops.add(
1554
            Ops.add(
1555
              # Error popup
1556
              _(
1557
                "<p>Errors occurred while restoring the repository configuration.</p>\n"
1558
              ) + "<p>",
1559
              Pkg.LastError
1560
            ),
1561
            "</p>"
1562
          ),
1563
          50,
1564
          15,
1565
          Label.ContinueButton,
1566
          Label.CancelButton,
1567
          :focus_no
1568
        )
1569

1570
        # really continue?
1571
        if !cont
×
1572
          Wizard.CloseDialog
×
1573
          return :abort
×
1574
        end
1575
      end
1576

1577
      # read known GPG keys
1578
      KeyManager.Read
×
1579

1580
      @sourceStatesIn = SortReposByPriority(Pkg.SourceEditGet)
×
1581
      Builtins.y2milestone("Found repositories: %1", @sourceStatesIn)
×
1582
      @sourceStatesOut = deep_copy(@sourceStatesIn)
×
1583

1584
      srv_aliases = Pkg.ServiceAliases
×
1585
      # get the current services
1586
      Builtins.foreach(srv_aliases) do |srv_alias|
×
1587
        @serviceStatesIn = Builtins.add(
×
1588
          @serviceStatesIn,
1589
          Pkg.ServiceGet(srv_alias)
1590
        )
1591
      end
1592

1593
      Builtins.y2milestone("Loaded services: %1", @serviceStatesIn)
×
1594

1595
      @serviceStatesOut = deep_copy(@serviceStatesIn)
×
1596

1597
      aliases = {
×
1598
        "summary" => -> { SummaryDialog() },
×
1599
        "type"    => -> { StartTypeDialog() },
×
1600
        "edit"    => -> { StartEditDialog() },
×
1601
        "store"   => -> { StartStoreSource() },
×
1602
        "keymgr"  => [-> { RunGPGKeyMgmt(false) }, true]
×
1603
      }
1604

1605
      sequence = {
×
1606
        "ws_start" => "summary",
1607
        "summary"  => {
1608
          add:     "type",
1609
          edit:    "edit",
1610
          key_mgr: "keymgr",
1611
          abort:   :abort,
1612
          next:    :next
1613
        },
1614
        "keymgr"   => { next: "summary", abort: "summary" },
1615
        "type"     => { next: "edit", finish: "store", abort: :abort },
1616
        "edit"     => { next: "store", abort: :abort },
1617
        "store"    => { next: "summary", abort: "summary" }
1618
      }
1619

1620
      Builtins.y2milestone("Starting repository sequence")
×
1621
      ret = Sequencer.Run(aliases, sequence)
×
1622

1623
      UI.CloseDialog
×
1624
      ret
×
1625
    end
1626

1627
    # Handle the "Delete" button in the service view
1628
    # @param [Integer] current index of the selected item in the table
1629
    def service_delete_handler(current)
1✔
1630
      selected_service = @serviceStatesOut[current] || {}
×
1631

1632
      service_alias = selected_service["alias"]
×
1633
      msg = _("The services of type 'plugin' cannot be removed.")
×
1634
      return if !plugin_service_check(service_alias, msg)
×
1635

1636
      # yes-no popup
1637
      return if !Popup.YesNo(
×
1638
        Builtins.sformat(
1639
          _("Delete service %1\nand its repositories?"),
1640
          selected_service["name"]
1641
        )
1642
      )
1643

1644
      RemoveReposFromService(service_alias)
×
1645

1646
      deleteService(current)
×
1647
      fillTable(@repository_view, @displayed_service)
×
1648
      fillCurrentRepoInfo
×
1649

1650
      # refresh also the combobox widget
1651
      UpdateCombobox()
×
1652
    end
1653

1654
    # Handle the "Delete" button in the repository view
1655
    # @param [Integer] global_current index of the repository in the @sourceStatesOut
1656
    def repo_delete_handler(global_current)
1✔
1657
      repo = @sourceStatesOut[global_current] || {}
×
1658

1659
      msg = _("The repositories belonging to a service of type 'plugin' cannot be removed.")
×
1660
      return if !repo["service"].to_s.empty? && !plugin_service_check(repo["service"], msg)
×
1661

1662
      # yes-no popup
1663
      return if !Popup.YesNo(_("Delete the selected repository from the list?"))
×
1664

1665
      deleteSource(global_current)
×
1666
      fillTable(@repository_view, @displayed_service)
×
1667
      fillCurrentRepoInfo
×
1668
    end
1669

1670
    # Handle the "Enable" checkbox in the repository view
1671
    # @param [Hash] source_state the current state of the repository or service
1672
    # @param [Integer] global_current index of the repository in the @sourceStatesOut
1673
    # @param [Integer] current index of the selected item in the table
1674
    def repo_enable_handler(source_state, global_current, current)
1✔
1675
      repo = @sourceStatesOut[global_current] || {}
×
1676
      if !repo["service"].to_s.empty? && !plugin_service_check(repo["service"], repo_change_msg)
×
1677
        return
×
1678
      end
1679

1680
      warn_service_repository(source_state)
×
1681
      state = !source_state["enabled"]
×
1682
      # corresponds to the "Enable/Disable" button
1683
      state_symbol = state ? UI.Glyph(:CheckMark) : ""
×
1684
      UI.ChangeWidget(Id(:table), term(:Item, current, 1), state_symbol)
×
1685
      source_state["enabled"] = state
×
1686
      @sourceStatesOut[global_current] = source_state
×
1687
    end
1688

1689
    # Handle the "Enable" checkbox in the service view
1690
    # @param [Integer] current index of the selected item in the table
1691
    def service_enable_handler(current)
1✔
1692
      srv = @serviceStatesOut[current]
×
1693
      return if !srv
×
1694

1695
      log.info("Selected service: #{srv}")
×
1696
      state = !srv["enabled"]
×
1697

1698
      # disable/enable the repositories belonging to the service
1699
      service_alias = srv["alias"]
×
1700
      return if !plugin_service_check(service_alias, plugin_change_msg)
×
1701

1702
      SetReposStatusFromService(service_alias, state)
×
1703

1704
      # update the table
1705
      state_symbol = state ? UI.Glyph(:CheckMark) : ""
×
1706
      UI.ChangeWidget(Id(:table), term(:Item, current, 0), state_symbol)
×
1707

1708
      # store the change
1709
      srv["enabled"] = state
×
1710
      @serviceStatesOut[current] = srv
×
1711
    end
1712

1713
    # Handle the "Autorefresh" checkbox in the repository view
1714
    # @param [Hash] source_state the current state of the repository or service
1715
    # @param [Integer] global_current index of the repository in the @sourceStatesOut
1716
    # @param [Integer] current index of the selected item in the table
1717
    def repo_autorefresh_handler(source_state, global_current, current)
1✔
1718
      source_id = source_state["SrcId"]
×
1719
      src_data = Pkg.SourceGeneralData(source_id)
×
1720
      return if !plugin_service_check(source_state["service"], repo_change_msg)
×
1721

1722
      warn_service_repository(source_state)
×
1723

1724
      type = src_data["type"]
×
1725
      state = !source_state["autorefresh"]
×
1726

1727
      if type == "PlainDir" && state
×
1728
        # popup message
1729
        Popup.Message(_("For the selected repository, refresh\ncannot be set."))
×
1730
        return
×
1731
      end
1732

1733
      new_symbol = state ? UI.Glyph(:CheckMark) : ""
×
1734
      UI.ChangeWidget(Id(:table), term(:Item, current, 2), new_symbol)
×
1735

1736
      source_state["autorefresh"] = state
×
1737
      @sourceStatesOut[global_current] = source_state
×
1738
    end
1739

1740
    # Handle the "Autorefresh" checkbox in the service view
1741
    # @param [Integer] current index of the selected item in the table
1742
    def service_autorefresh_handler(current)
1✔
1743
      srv = @serviceStatesOut[current]
×
1744
      log.info("Selected service: #{srv}")
×
1745

1746
      service_alias = srv["alias"]
×
1747
      return if !plugin_service_check(service_alias, plugin_change_msg)
×
1748

1749
      state = !srv["autorefresh"]
×
1750
      # update the table
1751
      new_symbol = state ? UI.Glyph(:CheckMark) : ""
×
1752
      UI.ChangeWidget(Id(:table), term(:Item, current, 1), new_symbol)
×
1753

1754
      # store the change
1755
      srv["autorefresh"] = state
×
1756
      @serviceStatesOut[current] = srv
×
1757
    end
1758

1759
    # Handle the "Priority" field in the repository view
1760
    # @param [Hash] source_state the current state of the repository or service
1761
    # @param [Integer] global_current index of the repository in the @sourceStatesOut
1762
    # @param [Integer] current index of the selected item in the table
1763
    def repo_priority_handler(source_state, global_current, current)
1✔
1764
      return if !plugin_service_check(source_state["service"], repo_change_msg)
×
1765

1766
      warn_service_repository(source_state)
×
1767
      # refresh the value in the table
1768
      new_priority = UI.QueryWidget(Id(:priority), :Value)
×
1769
      log.debug("New priority: #{new_priority}")
×
1770

1771
      UI.ChangeWidget(
×
1772
        Id(:table),
1773
        term(:Item, current, 0),
1774
        PriorityToString(new_priority)
1775
      )
1776
      source_state["priority"] = new_priority
×
1777
      @sourceStatesOut[global_current] = source_state
×
1778
    end
1779

1780
    # Handle the "Keep packages" check box in the repository view
1781
    # @param [Hash] source_state the current state of the repository or service
1782
    # @param [Integer] global_current index of the repository in the @sourceStatesOut
1783
    def repo_keeppackages_handler(source_state, global_current)
1✔
1784
      return if !plugin_service_check(source_state["service"], repo_change_msg)
×
1785

1786
      warn_service_repository(source_state)
×
1787

1788
      # refresh the value in the table
1789
      new_keep = UI.QueryWidget(Id(:keeppackages), :Value)
×
1790
      log.info("New keep packages option: #{new_keep}")
×
1791

1792
      source_state["keeppackages"] = new_keep
×
1793
      @sourceStatesOut[global_current] = source_state
×
1794
    end
1795

1796
    # Handle the "Edit" button in the repository view
1797
    # @param [Hash] source_state the current state of the repository or service
1798
    # @param [Integer] global_current index of the repository in the @sourceStatesOut
1799
    def repo_replace_handler(source_state, global_current)
1✔
1800
      id = source_state["SrcId"]
×
1801
      generalData = Pkg.SourceGeneralData(id)
×
1802

1803
      return if !plugin_service_check(generalData["service"], repo_change_msg)
×
1804

1805
      # use the full URL (incl. the password) when editing it
1806
      url2 = Pkg.SourceRawURL(id)
×
1807
      old_url = url2
×
1808
      plaindir = Ops.get_string(generalData, "type", "YaST") == @plaindir_type
×
1809

1810
      repo_name = source_state.fetch("raw_name", "")
×
1811
      # if the repository does not define a name then "raw_name" is empty,
1812
      # display "name" which contains the repository alias in that case
1813
      repo_name = source_state.fetch("name", "") if repo_name.empty?
×
1814

1815
      SourceDialogs.SetRepoName(repo_name)
×
1816

1817
      begin
1818
        url2 = SourceDialogs.EditPopupType(url2, plaindir)
×
1819

1820
        break if Builtins.size(url2).zero?
×
1821

1822
        same_url = url2 == old_url
×
1823

1824
        Builtins.y2debug(
×
1825
          "same_url: %1 (old: %2, new: %3)",
1826
          same_url,
1827
          old_url,
1828
          url2
1829
        )
1830

1831
        # special check for cd:// and dvd:// repositories
1832
        if !same_url
×
1833
          new_url_parsed = URL.Parse(url2)
×
1834
          old_url_parsed = URL.Parse(old_url)
×
1835

1836
          new_url_scheme = Builtins.tolower(
×
1837
            Ops.get_string(new_url_parsed, "scheme", "")
1838
          )
1839
          old_url_scheme = Builtins.tolower(
×
1840
            Ops.get_string(old_url_parsed, "scheme", "")
1841
          )
1842

1843
          # ignore cd:// <-> dvd:// changes if the path is not changed
1844
          if optical?(new_url_scheme) && optical?(old_url_scheme) && (Ops.get_string(
×
1845
            new_url_parsed, "path", ""
1846
          ) ==
×
1847
                Ops.get_string(old_url_parsed, "path", ""))
1848
            Pkg.SourceChangeUrl(
×
1849
              Ops.get_integer(source_state, "SrcId", -1),
1850
              url2
1851
            )
1852
            same_url = true
×
1853
          end
1854
        end
1855

1856
        if !same_url || plaindir != SourceDialogs.IsPlainDir
×
1857
          warn_service_repository(source_state)
×
1858

1859
          Builtins.y2milestone(
×
1860
            "URL or plaindir flag changed, recreating the source"
1861
          )
1862
          # copy the refresh flag
1863

1864
          # get current alias
1865
          alias_name = Ops.get_string(generalData, "alias", "alias")
×
1866
          Builtins.y2milestone("Reusing alias: %1", alias_name)
×
1867

1868
          createResult = createSourceWithAlias(
×
1869
            url2,
1870
            SourceDialogs.IsPlainDir,
1871
            Ops.get_boolean(source_state, "do_refresh", false),
1872
            SourceDialogs.GetRepoName,
1873
            alias_name
1874
          )
1875
          if createResult == :ok
×
1876
            # restore the origonal properties (enabled, autorefresh, keeppackages)
1877
            # the added repository is at the end of the list
1878
            idx = Ops.subtract(Builtins.size(@sourceStatesOut), 1)
×
1879
            addedSource = Ops.get(@sourceStatesOut, idx, {})
×
1880

1881
            Builtins.y2milestone("Orig repo: %1", source_state)
×
1882
            Builtins.y2milestone("Added repo: %1", addedSource)
×
1883

1884
            if addedSource != {}
×
1885
              auto_refresh = Ops.get_boolean(
×
1886
                source_state,
1887
                "autorefresh",
1888
                true
1889
              )
1890
              keeppackages = Ops.get_boolean(
×
1891
                source_state,
1892
                "keeppackages",
1893
                false
1894
              )
1895
              enabled = Ops.get_boolean(source_state, "enabled", true)
×
1896
              priority = Ops.get_integer(
×
1897
                source_state,
1898
                "priority",
1899
                @default_priority
1900
              )
1901
              service = source_state["service"] || ""
×
1902
              Builtins.y2milestone(
×
1903
                "Restoring the original properties: enabled: %1, autorefresh: %2, " \
1904
                "keeppackages: %3, priority: %4, service: %5",
1905
                enabled,
1906
                auto_refresh,
1907
                keeppackages,
1908
                priority,
1909
                service
1910
              )
1911

1912
              # set the original properties
1913
              Ops.set(addedSource, "autorefresh", auto_refresh)
×
1914
              Ops.set(addedSource, "keeppackages", keeppackages)
×
1915
              Ops.set(addedSource, "enabled", enabled)
×
1916
              Ops.set(addedSource, "priority", priority)
×
1917
              Ops.set(addedSource, "service", service)
×
1918

1919
              # get the ID of the old repo and mark it for removal
1920
              srcid = Ops.get_integer(
×
1921
                @sourceStatesOut,
1922
                [global_current, "SrcId"],
1923
                -1
1924
              )
1925
              if srcid != -1
×
1926
                @sourcesToDelete = Builtins.add(@sourcesToDelete, srcid)
×
1927
                SourceManager.just_removed_sources = Builtins.add(
×
1928
                  SourceManager.just_removed_sources,
1929
                  srcid
1930
                )
1931
              end
1932

1933
              # replace the data
1934
              Ops.set(@sourceStatesOut, global_current, addedSource)
×
1935
              # remove the duplicate at the end
1936
              @sourceStatesOut = Builtins.remove(@sourceStatesOut, idx)
×
1937

1938
              new_raw_name = addedSource.fetch("raw_name", "")
×
1939
              new_name = Yast::Pkg.ExpandedName(new_raw_name)
×
1940

1941
              # refresh only the name and URL in the table
1942
              UI.ChangeWidget(Id(:table), Cell(global_current, 3), new_name)
×
1943
              UI.ChangeWidget(Id(:table), Cell(global_current, 5), url2)
×
1944

1945
              fillCurrentRepoInfo
×
1946
            end
1947
          end
1948
        else
1949
          Builtins.y2milestone(
×
1950
            "URL is the same, not recreating the source"
1951
          )
1952

1953
          new_raw_name = SourceDialogs.GetRepoName
×
1954
          if new_raw_name == source_state.fetch("raw_name", "")
×
1955
            Builtins.y2milestone(
×
1956
              "The repository name has not been changed"
1957
            )
1958
          else
1959
            warn_service_repository(source_state)
×
1960

1961
            new_name = Yast::Pkg.ExpandedName(new_raw_name)
×
1962

1963
            source_state["name"] = new_name
×
1964
            source_state["raw_name"] = new_raw_name
×
1965
            @sourceStatesOut[global_current] = source_state
×
1966

1967
            # update only the name cell in the table
1968
            UI.ChangeWidget(Id(:table), Cell(global_current, 3), new_name)
×
1969

1970
            fillCurrentRepoInfo
×
1971
          end
1972

1973
          createResult = :ok
×
1974
        end
1975
      end while createResult == :again
×
1976
    end
1977

1978
    # Handle the "Edit" button in the service view
1979
    # @param [Integer] current index of the selected item in the table
1980
    def service_replace_handler(current)
1✔
1981
      service_info = Ops.get(@serviceStatesOut, current, {})
×
1982

1983
      service_alias = service_info["alias"]
×
1984
      return if !plugin_service_check(service_alias, plugin_change_msg)
×
1985

1986
      Builtins.y2milestone("Editing service %1...", current)
×
1987
      url2 = Ops.get_string(service_info, "raw_url", "")
×
1988
      old_url = url2
×
1989

1990
      SourceDialogs.SetRepoName(
×
1991
        Ops.get_string(service_info, "name", "")
1992
      )
1993
      begin
1994
        url2 = SourceDialogs.EditPopupService(url2)
×
1995

1996
        break if Builtins.size(url2).zero?
×
1997

1998
        if url2 == old_url
×
1999
          Builtins.y2milestone(
×
2000
            "URL is the same, not recreating the service"
2001
          )
2002
          entered_service_name = SourceDialogs.GetRepoName
×
2003
          old_service_name = Ops.get_string(service_info, "name", "")
×
2004

2005
          if old_service_name != entered_service_name
×
2006
            Builtins.y2milestone(
×
2007
              "Updating name of the service to '%1'",
2008
              entered_service_name
2009
            )
2010
            Ops.set(service_info, "name", entered_service_name)
×
2011
            Ops.set(@serviceStatesOut, current, service_info)
×
2012
            fillTable(@repository_view, @displayed_service)
×
2013
            fillCurrentRepoInfo
×
2014
            createResult = :ok
×
2015

2016
            # update the reference
2017
            @sourceStatesOut = Builtins.maplist(@sourceStatesOut) do |src_state|
×
2018
              if Ops.get_string(src_state, "service", "") == old_service_name
×
2019
                Ops.set(src_state, "service", entered_service_name)
×
2020
              end
2021
              deep_copy(src_state)
×
2022
            end
2023

2024
            # refresh also the combobox widget
2025
            UpdateCombobox()
×
2026
          end
2027
        else
2028
          Builtins.y2milestone(
×
2029
            "URL of the service has been changed, recreating the service"
2030
          )
2031
          # createSource() can potentially create a repository instead of a service
2032
          # Probe for a service first must be done before creating a new service
2033
          service_type = Pkg.ServiceProbe(url2)
×
2034
          Builtins.y2milestone("Probed service type: %1", service_type)
×
2035

2036
          if !service_type.nil? && service_type != "NONE"
×
2037
            createResult = createSource(
×
2038
              url2,
2039
              false,
2040
              false,
2041
              SourceDialogs.GetRepoName
2042
            )
2043
            if createResult == :ok
×
2044
              deleteService(current)
×
2045
              fillTable(@repository_view, @displayed_service)
×
2046
              fillCurrentRepoInfo
×
2047

2048
              # refresh also the combobox widget
2049
              UpdateCombobox()
×
2050
            end
2051
          else
2052
            Report.Error(
×
2053
              Builtins.sformat(
2054
                _("There is no service at URL:\n%1"),
2055
                url2
2056
              )
2057
            )
2058
          end
2059
        end
2060
      end while createResult == :again
×
2061
    end
2062

2063
    # The message displayed when trying to change a plugin service
2064
    def plugin_change_msg
1✔
2065
      # TRANSLATORS: An error message
2066
      _("The services of type 'plugin' cannot be changed.")
×
2067
    end
2068

2069
    # The message displayed when trying to change a repository belonging
2070
    # to a plugin service
2071
    def repo_change_msg
1✔
2072
      # TRANSLATORS: An error message
2073
      _("The repositories belonging to a service of type 'plugin' cannot be changed.")
×
2074
    end
2075

2076
    # Check whether the service is of type "plugin", if yes display the message
2077
    # @see https://doc.opensuse.org/projects/libzypp/SLE12SP2/zypp-plugins.html#plugin-services
2078
    # @see https://doc.opensuse.org/projects/libzypp/SLE12SP2/zypp-services.html
2079
    # @param [String] service_alias Alias of the service
2080
    # @param [String] msg Error message displayed
2081
    # @return [Boolean] true if type of service is not "plugin" or service does not exist,
2082
    #                   false otherwise
2083
    def plugin_service_check(service_alias, msg)
1✔
2084
      # check whether this is a repo from a plugin based service
2085
      serv_info = Pkg.ServiceGet(service_alias) || {}
4✔
2086

2087
      return true if serv_info["type"] != "plugin"
4✔
2088

2089
      Popup.Message(msg)
2✔
2090
      false
2✔
2091
    end
2092

2093
    # Shows a warning message when repository managed by a service
2094
    # @param [Hash] source_state the current state of the repository or service
2095
    def warn_service_repository(source_state)
1✔
2096
      return if source_state["service"].to_s.empty?
3✔
2097
      return if @services_repos.include?(source_state["SrcId"])
2✔
2098

2099
      msg = format(
1✔
2100
        _("Repository '%{name}' is managed by service '%{service}'.\n"\
2101
          "Your manual changes might be reset by the next service refresh!"),
2102
        name:    source_state["name"],
2103
        service: source_state["service"]
2104
      )
2105
      Popup.Warning(msg)
1✔
2106
      @services_repos.push(source_state["SrcId"])
1✔
2107
    end
2108

2109
    OPTICAL = ["cd", "dvd"].freeze
1✔
2110
    def optical?(scheme)
1✔
2111
      OPTICAL.include?(scheme)
5✔
2112
    end
2113
  end
2114
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

© 2025 Coveralls, Inc