Class: Origen::Utility::DesignSync

Inherits:
Object
  • Object
show all
Defined in:
lib/origen/utility/design_sync.rb

Overview

Ruby API to interface with Design Sync

Instance Method Summary collapse

Instance Method Details

#cancel(_target, options = {}) ⇒ Object

Cancel a checkout of a specific target which should be an absolute path to the target file, or wildcard expression

Options:

  • :rec # Do a recursive cancel, false by default

  • :force # Force cancel (overwrite local edits), false by default

  • :exclude # Supply filenames to exclude or wildcard, e.g. “.lst,.S19”

  • :keep # Keep editable copy of the files post cancel, false by default

Example

# Cancel every checkout in Origen.root
cancel("#{Origen.root}/*", :rec => true, :force => true)


172
173
174
175
176
# File 'lib/origen/utility/design_sync.rb', line 172

def cancel(_target, options = {})
  # Note "-verbose" is not a valid option for dssc cancel
  cmd = "dssc cancel #{keep(options)} #{rec(options)} #{force(options)} #{exclude(options)}"
  launch(cmd)
end

#changed_objects(target, previous_tag, options = {}) ⇒ Object

Returns a hash containing files that have changed vs. the previous tag, this is organized as follows:

{
  :added => [],    # Paths to files that have been added since the previous tag
  :removed => [],  # Paths to files that have been removed since the previous tag
  :changed => [],  # Paths to files that have changed since the previous tag
}


318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/origen/utility/design_sync.rb', line 318

def changed_objects(target, previous_tag, options = {})
  options = {
  }.merge(options)
  # We need to parse the following data from the output, ignore everything else
  # which will mostly refer to un-managed files.
  #
  # Added since previous version...
  # 1.12                                          First only         source_setup
  # Removed since previous version...
  #                        1.13                   Second only        lib/history
  # Modified since previous version...
  # 1.32                   1.31                   Different versions lib/origen/application.rb
  # Modified since previous version including a local edit...
  # 1.7 (Locally Modified) 1.7                    Different states   lib/origen/commands/rc.rb
  objects = {
    added: [], removed: [], changed: []
  }
  sys("dssc compare -rec -path -report silent -selector #{previous_tag} #{target}").each do |line|
    unless line =~ /Unmanaged/
      # http://www.rubular.com/r/GoNYB75upB
      if line =~ /\s*(\S+)\s+First only\s+(\S+)\s*/
        objects[:added] << Regexp.last_match[2]
      # http://www.rubular.com/r/Xvh32Lm4hS
      elsif line =~ /\s*(\S+)\s+Second only\s+(\S+)\s*/
        objects[:removed] << Regexp.last_match[2]
      # http://www.rubular.com/r/tvTHod9Mye
      elsif line =~ /\s*\S+\s+(\(Locally Modified\))?\s*(\S+)\s+Different (versions|states)\s+(\S+)\s*/
        objects[:changed] << Regexp.last_match[4]
      end
    end
  end
  objects
end

#changed_objects?(*args) ⇒ Boolean

Check if the supplied directory has any changed objects vs the previous tag See DesignSync#changed_objects for available options.

Returns:

  • (Boolean)


305
306
307
308
# File 'lib/origen/utility/design_sync.rb', line 305

def changed_objects?(*args)
  objects = changed_objects(*args)
  objects[:added].size > 0 || objects[:removed].size > 0 || objects[:changed].size > 0
end

#check_in(target, options = {}) ⇒ Object

Check in a specific target which should be an absolute path to the target file, or wildcard expression.

Options:

  • :rec # Do a recursive check-in, false by default

  • :comment # Supply a comment to go with the check-in

  • :new # Allow check in of new files (i.e. add the file to revision control)

  • :verbose # Display output to terminal, false by default

  • :skip # Allow check in to skip over a newer version of the file if it exists

  • :keep # Keep editable copy of the files post check-in, false by default

Example

# Check-in everything in Origen.root
check_in("#{Origen.root}/*", :rec => true, :com => "Periodic checkin, still in development")


98
99
100
101
102
103
104
105
# File 'lib/origen/utility/design_sync.rb', line 98

def check_in(target, options = {})
  options = {
    keep:    true
  }.merge(options)
  # FYI: for debug use '-dryrun' option to 'dssc ci' command
  cmd = "dssc ci #{keep(options)} #{rec(options)} #{new(options)} #{com(options)} #{branch(options)} #{options[:skip] ? '-skip' : ''} #{target}"
  launch(cmd, options[:verbose])
end

#check_out(target, options = {}) ⇒ Object

Check out a specific target which should be an absolute path to the target file, or wildcard expression.

Options:

  • :rec # Do a recursive checkout, false by default

  • :lock # Check out with a lock (overrides get option due to DesignSync get/lock incompatibility)

  • :version # Specific tag or version number, will get latest by default

  • :force # Force check out, false by default

  • :verbose # Display output to terminal, false by default

  • :get # Fetch locally editable copies, true by default (unless lock is set)

Example

# Checkout everything in Origen.root
check_out("#{Origen.root}/*", :rec => true)


74
75
76
77
78
79
80
# File 'lib/origen/utility/design_sync.rb', line 74

def check_out(target, options = {})
  options = {
    get: true
  }.merge(options)
  cmd = "dssc co #{rec(options)} #{get(options)} #{loc(options)} #{ver(options)} #{force(options)} -nocomment #{target}"
  launch(cmd, options[:verbose])
end

#container_directory(pathname) ⇒ Object

Will recursively move back up the directory tree from the given directory and return the first one that is not part of a Design Sync workspace.

The supplied pathname should be an absolute Pathname instance.



383
384
385
386
387
388
389
# File 'lib/origen/utility/design_sync.rb', line 383

def container_directory(pathname)
  if managed_by_design_sync?(pathname)
    container_directory(pathname.parent)
  else
    pathname
  end
end

#diff_cmd(options = {}) ⇒ Object



352
353
354
355
356
357
358
# File 'lib/origen/utility/design_sync.rb', line 352

def diff_cmd(options = {})
  if options[:version]
    "dssc diff -gui -ver #{options[:version]}"
  else
    'dssc diff -gui'
  end
end

#full_path_prefixObject



293
294
295
296
297
298
299
300
301
# File 'lib/origen/utility/design_sync.rb', line 293

def full_path_prefix
  @full_path_prefix ||= begin
    if Origen.running_on_windows?
      'file:///'
    else
      'file://'
    end
  end
end

#import(file, vault, version, destination = false) ⇒ Object

Import a file to the local workspace from another vault, where the vault argument must include the full path to the requested file. You can optionally supply a destination for where you want the file to end up, if no destination is supplied the file will end up in the PWD.

Example

# Import this file and save it in Origen.root
file = "design_sync.rb"
vault = "sync://sync-15088:15088/Projects/common_tester_blocks/origen/lib/sys"
version = "v0.1.0"   # Version can be any valid DS identifier, e.g. a version number or tag

import(file, vault, version, Origen.root)


45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/origen/utility/design_sync.rb', line 45

def import(file, vault, version, destination = false)
  puts 'Importing from DesignSync...'
  puts "#{vault}/#{file} #{version}"
  unless sys("dssc import -version #{version} -force #{vault} #{file}")[0] =~ /Success/
    fail "Error importing #{file} from Design Sync"
  end
  if Origen.running_on_windows?
    sys("move /Y #{file} #{destination}/.") if destination
  else
    sys("mv -f #{file} #{destination}/.") if destination
  end
end

#initialize_dir(dir, vault) ⇒ Object

Initializes the given directory with the given vault reference



392
393
394
395
396
# File 'lib/origen/utility/design_sync.rb', line 392

def initialize_dir(dir, vault)
  Dir.chdir dir do
    sys "dssc setvault #{vault} ."
  end
end

#managed_by_design_sync?(path, _options = {}) ⇒ Boolean

Returns true if the given file is known to Design Sync

Example

managed_by_design_sync?("#{Origen.root}/config/application.rb")

Returns:

  • (Boolean)


365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/origen/utility/design_sync.rb', line 365

def managed_by_design_sync?(path, _options = {})
  res = sys "dssc url vault #{path}"
  if res.empty?
    false
  else
    if res.first =~ /^file:/ || res.first =~ /There is no object with that name/
      false
    else
      true
    end
  end
end

#modified_objects(target, options = {}) ⇒ Object

Returns an array of paths to modified files, caches result for performance, set :refresh => true to clear cache. The target should be an absolute path to the directory you want to query.

Options:

  • :rec # Do a recursive search, false by default

  • :exclude # Supply filenames to exclude or wildcard, e.g. “.lst,.S19”

  • :refresh # Force a new search, false by default

Example

# Get all modified files in my project workspace
files = modified_objects(Origen.root, :rec => true)

NOTE: -unmanaged and -managed are mutually exclusive, specifying both does neither!

-unmanaged : show only objects not under revision control
-managed   : show only objects under revision control
-modified  : show locally modified files in workspace (includes unmanaged objects)
-changed   : shows not up-to-date files.  Includes both locally modified and newer verions in vault.
             Overrides -modified.


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/origen/utility/design_sync.rb', line 246

def modified_objects(target, options = {})
  options = {
    managed: true,  # by default handle managed (to permit for unmanaged case)
    remote:  false,  # includes files possibly modified by others in repository
  }.merge(options)
  # The result of this method is cached for future calls (method called twice actually)
  @objects = nil if options[:refresh]
  @needs_update_objects = nil if options[:refresh]

  if options[:remote]
    return @needs_update_objects if @needs_update_objects
  else
    return @objects if @objects
  end

  # Since DesignSync does not supply an option to only list files that need update (!), have to run with
  # -changed option then again without and difference the 2 arrays!
  if options[:remote]
    all_objects = sys("dssc ls #{rec(options)} #{exclude(options)} #{managed(options)} #{dssc_path(options)} -report N -modified #{unmanaged(options)} -changed -format text #{target}").reject do |item|
      # removes extraneous lines
      item =~ /^(Name|Directory|---)/
    end
    all_objects.map! do |object|
      object.strip!  # Strip off any whitespace from all objects
      object.sub!(/^#{full_path_prefix}/, '')
      object.sub('|', ':')
    end
  end

  @objects = sys("dssc ls #{rec(options)} #{exclude(options)} #{managed(options)} #{dssc_path(options)} -report N -modified #{unmanaged(options)} -format text #{target}").reject do |item|
    # removes extraneous lines
    item =~ /^(Name|Directory|---)/
  end
  @objects.map! do |object|
    object.strip!  # Strip off any whitespace from all objects
    object.sub!(/^#{full_path_prefix}/, '')
    object.sub('|', ':')
  end

  # Now difference the lists if remote desired
  if options[:remote]
    return @needs_update_objects = all_objects - @objects
  else
    return @objects
  end
end

#modified_objects?(*args) ⇒ Boolean

Check if the supplied directory has any modified objects, will reflect the result from the last call unless :refresh => true. Returns true or false. See DesignSync#modified_objects for available options.

Example

modified_objects?                   # Takes a while to run while the workspace is queried
modified_objects?                   # Runs very quickly and returns the cached answer
modified_objects?(:refresh => true) # Takes a while to run while the workspace is queried

Returns:

  • (Boolean)


215
216
217
# File 'lib/origen/utility/design_sync.rb', line 215

def modified_objects?(*args)
  modified_objects(*args).size > 0
end

#populate(target, options = {}) ⇒ Object

Almost the same as DesignSync#check_out but accepts some different options.

Options:

  • :rec # Do a recursive populate, false by default

  • :version # Specific tag or version number, will get latest by default

  • :force # Force populate (overwrite local edits), false by default

  • :unify # Unify the workspace (remove any retired files you currently have checked out)

  • :exclude # Supply filenames to exclude or wildcard, e.g. “.lst,.S19”

  • :verbose # Display output to terminal, false by default

  • :get # Fetch locally editable copies, true by default

  • :merge # Merge local edits into latest files, false by default



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/origen/utility/design_sync.rb', line 190

def populate(target, options = {})
  options = { unify:       true,
              incremental: false,
              replace:     false,
              get:         true,
              merge:       false
            }.merge(options)
  inc = options[:incremental] ? '-inc' : ''
  replace = options[:replace] ? '-replace' : ''
  cmd = "dssc pop #{inc} #{replace} #{rec(options)} #{force(options)} #{merge(options)} #{get(options)} #{ver(options)} #{uni(options)} #{exclude(options)} #{target}"
  successful = launch(cmd, options[:verbose])
  unless successful
    fail "Something went wrong when populating #{target} from DesignSync!"
  end
end

#remote_check_in(dir, options = {}) ⇒ Object

Check in the contents of the given directory to a remote vault location, that is a vault location that is not associated with the workspace that the given files are in.

Anything found in the given directory will be checked in, even files which are not currently under revision control.

No attempt will be made to merge the current vault contents with the local data, the local data will always be checked in as lastest.

A tag can be optionally supplied and if present will be applied to the files post check in.

Examples:


ds.remote_check_in("#{Origen.root}/output/j750", :vault => "sync://sync-15088:15088/Projects/common_tester_blocks/origen_training/j750", :tag => Origen.app.version)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/origen/utility/design_sync.rb', line 121

def remote_check_in(dir, options = {})
  Origen.deprecate 'Use Origen::RevisionControl::DesignSync.remote_check_in instead'
  options = {
    verbose: true,
    rec:     true,
    keep:    true,
    new:     true,
    skip:    true,
    replace: true
  }.merge(options)

  dir = Pathname.new(dir)
  fail "Directory does not exist: #{dir}" unless dir.exist?
  fail "Only directories are supported by remote_check_in, this is not a directory: #{dir}" unless dir.directory?
  fail 'No vault option supplied to remote_check_in!' unless options[:vault]
  scratch = Pathname.new("#{Origen.app.workspace_manager.imports_directory}/design_sync/scratch")
  FileUtils.rm_rf(scratch) if scratch.exist?
  FileUtils.mkdir_p(scratch)
  FileUtils.cp_r("#{dir}/.", scratch)
  remove_dot_syncs!(scratch)
  launch("dssc setvault #{options[:vault]} #{scratch}", options[:verbose])
  check_in(scratch, options)
  tag(scratch, options[:tag], options) if options[:tag]
  FileUtils.rm_rf(scratch)
end

#remove_dot_syncs!(dir, _options = {}) ⇒ Object

Recursively remove all .SYNC directories from the given directory



148
149
150
151
152
153
154
155
156
# File 'lib/origen/utility/design_sync.rb', line 148

def remove_dot_syncs!(dir, _options = {})
  Origen.deprecate 'Use Origen::RevisionControl::DesignSync.remove_dot_syncs! instead'
  dir = Pathname.new(dir)
  fail "Directory does not exist: #{dir}" unless dir.exist?
  fail "Only directories are supported by remove_dot_syncs, this is not a directory: #{dir}" unless dir.directory?
  Dir.glob("#{dir}/**/.SYNC").sort.each do |dot_sync|
    FileUtils.rm_rf(dot_sync)
  end
end

#selector(target) ⇒ Object

Returns the selector for the given object, which should be an absolute path to a file or directory



221
222
223
# File 'lib/origen/utility/design_sync.rb', line 221

def selector(target)
  sys("dssc url selector #{target}")[0]
end

#tag(target, tag, options = {}) ⇒ Object

Tag the target which is an absolute path to a file or directory.

Options

  • :rec # Recursive, false by default

  • :delete # Delete the given tag from the target, false by default

  • :replace # Replace any existing version of the given tag, false by default

  • :exclude # Supply filenames to exclude or wildcard, e.g. “.lst,.S19”

Example

tag(Origen.root, "my_release_001", :rec => true)
tag("#{Origen.root}/top/top_block.rb", "my_release_001")


18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/origen/utility/design_sync.rb', line 18

def tag(target, tag, options = {})
  options = { rec:     false,   # Set true to tag recursively
              delete:  false,
              replace: false
  }.merge(options)
  cmd = "dssc tag #{tag} #{exclude(options)} #{options[:replace] ? '-replace' : ''} #{rec(options)} #{options[:delete] ? '-delete' : ''} #{target}"
  if options[:debug]
    puts '**** DesignSync Debug ****'
    puts cmd
  else
    system(cmd)
  end
end

#vault(file_or_dir) ⇒ Object

Returns the vault reference to give local file or directory



399
400
401
# File 'lib/origen/utility/design_sync.rb', line 399

def vault(file_or_dir)
  (sys "dssc url vault #{file_or_dir}").first
end