net-scp 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1413e9916cf7c4d82160a87e9da29044528f7c32dc746d12a873ea4d902a940
4
- data.tar.gz: b0e33d71c6a78b8d263fd95408e23188c3c7e0bb274d52c1df6745bbc6793cc6
3
+ metadata.gz: b8d6b4ea9428a9cc3df98e388eb80ce0a6dd45021bad757992537f24dc954d38
4
+ data.tar.gz: 72ada8e9dc44cf7d7ffad414ccf8dfa90f1f3f875e83400acc6293e9523d8b03
5
5
  SHA512:
6
- metadata.gz: 46648015028eb41a2d7f269f4fe6baa430289da17f82c2945c5ef49ff4fa43085a966734d7e361a98b08cd91f7abf99f219eeebd954607bc74969f398e861ceb
7
- data.tar.gz: e307dc9bb8e181c76acb226ffc8b35f5c2002adbef0f027f8954b9e695cc8436b780a7f4316dba7b685a48048184676c20dacceb2db81d235dcf51a83045ddf5
6
+ metadata.gz: 76879f624878414b25e51abe5cfc88d078a99db6750b3b7c816454cae23c4d1d988201dd56af3ac3df21ac7b9c575a160c9eca44ccb731bfa332a6c3fe43651a
7
+ data.tar.gz: 41880eab49fcce9ae5e1f251f2360843941598b96496d26b33770449d53bf1b2ea15ef706af37d5af83370c57e0c878815d523eca2b974274dce43288953e318
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGES.txt CHANGED
@@ -1,3 +1,15 @@
1
+ === 4.2.0
2
+
3
+ * BREAKING: Require Ruby 2.6 or later. Bundler on Ruby 2.3-2.5 resolves to 4.1.3. [#114]
4
+ * Package only `lib`, `CHANGES.txt`, `LICENSE.txt` and `README.md` in the gem, about 40% smaller. Thanks @yuri-zubov [#118]
5
+ * An exception raised during a transfer, such as `upload!` of a missing local file or an error from a progress callback, no longer leaves the channel registered and re-raises on later operations on the same session; the original error is raised once, library-opened files are closed and caller-passed IO is left open. Thanks @ThomasSevestre and @OskarEichler [#107, #26, #97]
6
+
7
+ === 4.1.3
8
+
9
+ * Load again on Ruby 2.3-2.5 (4.1.2 needed 2.5), and declare `required_ruby_version >= 2.3` [#112, #110]
10
+ * Add a `quote:` option to `upload`/`download` for the remote path: `:posix` (default), `:windows` for Win32-OpenSSH under cmd.exe or PowerShell (double-quoted, `\` sent as `/`, paths containing `"`, `$`, `` ` ``, `%`, `!`, curly quotes, CR, LF or NUL rejected), `:none` to send the path unchanged to servers without a shell, or a callable. By default a leading `~` or `~/` is now left for the remote shell to expand to the home directory; such paths previously referred to a literal `~` entry in the login directory and usually failed. Thanks @ArtsiomMusin for the Windows patch in #34 [#109, #34, #9]
11
+ * Recursive uploads no longer abort on a broken symlink: it is skipped with a warning, the rest is uploaded, and a Net::SCP::Error listing the skipped paths is raised at the end, like OpenSSH scp. Based on #23 by @maage. [#108, #23]
12
+
1
13
  === 4.1.2
2
14
 
3
15
  * Security: Downloads no longer apply setuid, setgid or sticky bits sent by the server, check that a server-chosen local name matches the requested remote basename (as OpenSSH does since CVE-2019-6111), and refuse to follow an existing local symlink at a server-named path instead of writing through it. The local path passed by the caller may still be a symlink. O_NOFOLLOW suggested in net-sftp#162 by srosenhamer [#104]
data/README.md CHANGED
@@ -69,6 +69,24 @@ require 'uri/open-scp'
69
69
  data = open("scp://user@host/path/to/file.txt").read
70
70
  ```
71
71
 
72
+ The remote path is escaped for a POSIX shell, except that a leading `~` or
73
+ `~/` is left for the remote shell to expand to the home directory (`~user/` is
74
+ not expanded). Use the `quote:` option of `upload`/`download` for other
75
+ servers:
76
+
77
+ ```ruby
78
+ # Win32-OpenSSH (cmd.exe or PowerShell): the path is double-quoted and "\" becomes "/".
79
+ # Paths containing ", $, `, %, !, curly quotes, CR, LF or NUL raise ArgumentError.
80
+ scp.upload! "/local/path", "C:\\Program Files\\App\\file.txt", quote: :windows
81
+
82
+ # Servers that don't run a shell (MikroTik and other appliances): the path is
83
+ # sent unchanged. Never use this with untrusted paths.
84
+ scp.download! "flash/backup.rsc", "/local/backup.rsc", quote: :none
85
+
86
+ # Or quote it yourself
87
+ scp.upload! "/local/path", remote, quote: ->(path) { "'#{path}'" }
88
+ ```
89
+
72
90
  For more information, see Net::SCP.
73
91
 
74
92
  ## REQUIREMENTS:
@@ -49,7 +49,8 @@ module Net; class SCP
49
49
  directive = "D%04o %d %s\n" % [mode, 0, File.basename(channel[:current])]
50
50
  channel.send_data(directive)
51
51
  channel[:cwd] = channel[:current]
52
- channel[:stack] << Dir.entries(channel[:current]).reject { |i| i == "." || i == ".." }
52
+ entries = Dir.entries(channel[:current]).reject { |i| i == "." || i == ".." }
53
+ channel[:stack] << entries.reject { |i| skip_broken_symlink(channel, File.join(channel[:current], i)) }
53
54
  await_response(channel, :next_item)
54
55
  end
55
56
  end
@@ -124,6 +125,29 @@ module Net; class SCP
124
125
  end
125
126
  end
126
127
 
128
+ # Returns true if +path+ is a symlink whose target doesn't exist, after
129
+ # logging a warning and recording it for #raise_if_entries_skipped.
130
+ def skip_broken_symlink(channel, path)
131
+ return false unless File.symlink?(path) && !File.exist?(path)
132
+
133
+ lwarn { "#{path}: broken symlink, skipping" }
134
+ (channel[:skipped] ||= []) << path
135
+ true
136
+ end
137
+
138
+ # Once the remote has closed the channel, raises a Net::SCP::Error listing
139
+ # the entries skipped by #skip_broken_symlink, if any.
140
+ def raise_if_entries_skipped(channel)
141
+ return unless channel.closing? && channel[:skipped]
142
+
143
+ # Cleared so it raises once, as on_process keeps calling this until the close is flushed.
144
+ skipped, channel[:skipped] = channel[:skipped], nil
145
+ # A failed remote scp is reported by start_command's exit-status check instead.
146
+ return unless channel[:exit].to_i.zero?
147
+
148
+ raise Net::SCP::Error, "upload incomplete, skipped broken symlinks: #{skipped.map(&:inspect).join(', ')}"
149
+ end
150
+
127
151
  # If the :preserve option is set, send a 'T' directive and wait for the
128
152
  # server to respond before proceeding to either #upload_file_state or
129
153
  # #upload_directory_state, depending on what is being uploaded.
@@ -49,10 +49,10 @@ module Net
49
49
  MAJOR = 4
50
50
 
51
51
  # The minor component of this version of the Net::SSH library
52
- MINOR = 1
52
+ MINOR = 2
53
53
 
54
54
  # The tiny component of this version of the Net::SSH library
55
- TINY = 2
55
+ TINY = 0
56
56
 
57
57
  # The prerelease component of this version of the Net::SSH library
58
58
  # nil allowed
data/lib/net/scp.rb CHANGED
@@ -259,13 +259,24 @@ module Net
259
259
  #
260
260
  # * :recursive - the +local+ parameter refers to a local directory, which
261
261
  # should be uploaded to a new directory named +remote+ on the remote
262
- # server.
262
+ # server. Broken symlinks in it are skipped with a warning, and once
263
+ # everything else is uploaded a Net::SCP::Error listing them is raised.
263
264
  # * :preserve - the atime and mtime of the file should be preserved.
264
265
  # * :verbose - the process should result in verbose output on the server
265
266
  # end (useful for debugging).
266
267
  # * :chunk_size - the size of each "chunk" that should be sent. Defaults
267
268
  # to 2048. Changing this value may improve throughput at the expense
268
269
  # of decreasing interactivity.
270
+ # * :quote - how +remote+ is quoted in the scp command run by the remote
271
+ # shell. :posix (the default) escapes it for a POSIX shell, leaving a
272
+ # leading "~" or "~/" unescaped so it expands to the remote home
273
+ # directory ("~user/" is not expanded). :windows is for Win32-OpenSSH,
274
+ # whose shell may be cmd.exe or PowerShell: backslashes become "/", the
275
+ # path is wrapped in double quotes, and paths containing a double or curly
276
+ # quote, $, `, %, !, CR, LF or NUL raise ArgumentError. :none sends the
277
+ # path unchanged, for servers that don't run a shell (some routers and
278
+ # appliances); never use it with untrusted input. A callable is given
279
+ # +remote+ and returns the string to send.
269
280
  #
270
281
  # This method will return immediately, returning the Net::SSH::Connection::Channel
271
282
  # object that will support the upload. To wait for the upload to finish,
@@ -298,6 +309,7 @@ module Net
298
309
  # * :preserve - the atime and mtime of the file should be preserved.
299
310
  # * :verbose - the process should result in verbose output on the server
300
311
  # end (useful for debugging).
312
+ # * :quote - how +remote+ is quoted for the remote shell (see #upload).
301
313
  #
302
314
  # This method will return immediately, returning the Net::SSH::Connection::Channel
303
315
  # object that will support the download. To wait for the download to finish,
@@ -348,15 +360,14 @@ module Net
348
360
  # (See Net::SCP::Upload and Net::SCP::Download).
349
361
  def start_command(mode, local, remote, options={}, &callback)
350
362
  local = local.to_path if local.is_a?(Pathname)
351
- session.open_channel do |channel|
352
-
353
- if options[:shell]
354
- escaped_file = shellescape(remote).gsub(/'/) { |m| "'\\''" }
355
- command = "#{options[:shell]} -c '#{scp_command(mode, options)} #{escaped_file}'"
356
- else
357
- command = "#{scp_command(mode, options)} #{shellescape remote}"
358
- end
363
+ # Kept in channel[:remote] too, so a download's basename check sees "C:/a/b.txt" as b.txt.
364
+ remote = remote.to_s.tr("\\", "/") if options[:quote] == :windows
365
+ command = "#{scp_command(mode, options)} #{quote_remote(remote, options[:quote] || :posix)}"
366
+ if options[:shell]
367
+ command = "#{options[:shell]} -c '#{command.gsub("'") { "'\\''" }}'"
368
+ end
359
369
 
370
+ session.open_channel do |channel|
360
371
  channel.exec(command) do |ch, success|
361
372
  if success
362
373
  channel[:local ] = local
@@ -369,27 +380,30 @@ module Net
369
380
  channel[:error_string] = +''
370
381
 
371
382
  channel.on_close do
372
- # The close can be dispatched before on_process has consumed data that arrived with it.
373
- send("#{channel[:state]}_state", channel)
374
- # If we got an exit-status and it is not 0, something went wrong
375
- if !channel[:exit].nil? && channel[:exit] != 0
376
- raise Net::SCP::Error, 'SCP did not finish successfully ' \
377
- "(#{channel[:exit]}): #{channel[:error_string]}"
378
- end
379
- # A zero or missing exit-status does not prove the transfer completed.
380
- if channel[:state] != :finish
381
- message = +'SCP did not finish successfully (channel closed before end of transmission)'
382
- message << ": #{channel[:error_string]}" unless channel[:error_string].empty?
383
- raise Net::SCP::Error, message
383
+ begin
384
+ next if channel[:aborted]
385
+
386
+ # The close can be dispatched before on_process has consumed data that arrived with it.
387
+ process_state(channel)
388
+ # If we got an exit-status and it is not 0, something went wrong
389
+ if !channel[:exit].nil? && channel[:exit] != 0
390
+ raise Net::SCP::Error, 'SCP did not finish successfully ' \
391
+ "(#{channel[:exit]}): #{channel[:error_string]}"
392
+ end
393
+ # A zero or missing exit-status does not prove the transfer completed.
394
+ if channel[:state] != :finish
395
+ message = +'SCP did not finish successfully (channel closed before end of transmission)'
396
+ message << ": #{channel[:error_string]}" unless channel[:error_string].empty?
397
+ raise Net::SCP::Error, message
398
+ end
399
+ ensure
400
+ close_owned_io(channel)
384
401
  end
385
- ensure
386
- io = channel[:io]
387
- io.close if io && io != channel[:local] && !io.closed?
388
402
  end
389
403
  channel.on_data { |ch2, data| channel[:buffer].append(data) }
390
404
  channel.on_extended_data { |ch2, type, data| debug { data.chomp } }
391
405
  channel.on_request("exit-status") { |ch2, data| channel[:exit] = data.read_long }
392
- channel.on_process { send("#{channel[:state]}_state", channel) }
406
+ channel.on_process { process_state(channel) unless channel[:aborted] }
393
407
  else
394
408
  channel.close
395
409
  raise Net::SCP::Error, "could not exec scp on the remote host"
@@ -398,6 +412,25 @@ module Net
398
412
  end
399
413
  end
400
414
 
415
+ # Runs the action for the current state. If it raises, the transfer is
416
+ # aborted and the channel closed, so the error surfaces once and the
417
+ # session stays usable.
418
+ def process_state(channel)
419
+ send("#{channel[:state]}_state", channel)
420
+ rescue Exception
421
+ channel[:aborted] = true
422
+ close_owned_io(channel)
423
+ channel.close
424
+ raise
425
+ end
426
+
427
+ # Closes the IO opened by the library; an IO passed in by the caller is
428
+ # left open.
429
+ def close_owned_io(channel)
430
+ io = channel[:io]
431
+ io.close if io && io != channel[:local] && !io.closed?
432
+ end
433
+
401
434
  # Causes the state machine to enter the "await response" state, where
402
435
  # things just pause until the server replies with a 0 (see
403
436
  # #await_response_state), at which point the state machine will pick up
@@ -428,6 +461,7 @@ module Net
428
461
  # of the pipe, and allows the pipe to drain until the server closes it.
429
462
  def finish_state(channel)
430
463
  channel.eof!
464
+ raise_if_entries_skipped(channel)
431
465
  end
432
466
 
433
467
  # Invoked to report progress back to the client. If a callback was not
@@ -436,6 +470,29 @@ module Net
436
470
  channel[:callback].call(channel, name, sent, total) if channel[:callback]
437
471
  end
438
472
 
473
+ # Inside double quotes cmd.exe still expands % and !, PowerShell expands $ and `, and PowerShell also ends a string at U+2018..U+201E.
474
+ WINDOWS_UNSAFE = /["$`%!\r\n\0\u2018-\u201E]/
475
+
476
+ def quote_remote(remote, quote)
477
+ case quote
478
+ when :posix
479
+ remote = remote.to_s
480
+ return remote if remote == "~" || remote == "~/"
481
+ return "~/#{shellescape(remote[2..-1])}" if remote.start_with?("~/")
482
+ shellescape(remote)
483
+ when :windows
484
+ if remote.dup.force_encoding(Encoding::UTF_8) =~ WINDOWS_UNSAFE
485
+ raise ArgumentError, "remote path #{remote.inspect} contains a character that can't be quoted safely for a Windows shell"
486
+ end
487
+ "\"#{remote}\""
488
+ when :none
489
+ remote.to_s
490
+ else
491
+ raise ArgumentError, ":quote must be :posix, :windows, :none or a callable, got #{quote.inspect}" unless quote.respond_to?(:call)
492
+ quote.call(remote).to_s
493
+ end
494
+ end
495
+
439
496
  # Imported from ruby 1.9.2 shellwords.rb
440
497
  def shellescape(path)
441
498
  # Convert path to a string if it isn't already one.
data.tar.gz.sig CHANGED
@@ -1,2 +1 @@
1
- �bf3p�l��q�� E@P��a� �y?��i�v_���K��?��B�Q�x�4�U�RM�u�������й�<���H\��Յl�9��
2
- S#6 &�t����\�+��tBk�����޽P�P�g��{s����j����Nί�q+��5D7�(�^�ʘ��)�x0.���$�m�T f~:��%%{P��b��GO!��V#���i�7c���"���8L3;��HB�j���3�T���e �$:�A�?C
1
+ T.7 B����4�
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-scp
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
@@ -32,7 +32,7 @@ cert_chain:
32
32
  vNiMFH5yLu/tlav4xh+HlYscWVdFQIvd7f/Uxa+Vip1Pi16wmhnrE15z/vDX921v
33
33
  hukBRIoCEAuUgNVBh+L/C8aETzbf/77WU3Si/w==
34
34
  -----END CERTIFICATE-----
35
- date: 2026-10-25 00:00:00.000000000 Z
35
+ date: 2026-10-29 00:00:00.000000000 Z
36
36
  dependencies:
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: net-ssh
@@ -91,19 +91,9 @@ extra_rdoc_files:
91
91
  - LICENSE.txt
92
92
  - README.md
93
93
  files:
94
- - ".github/pull_request_template.md"
95
- - ".github/workflows/changelog.yml"
96
- - ".github/workflows/ci.yml"
97
- - ".gitignore"
98
94
  - CHANGES.txt
99
- - CONTRIBUTING.md
100
- - Gemfile
101
95
  - LICENSE.txt
102
- - Manifest
103
96
  - README.md
104
- - Rakefile
105
- - SECURITY.md
106
- - changelog.d/README.md
107
97
  - lib/net/scp.rb
108
98
  - lib/net/scp/download.rb
109
99
  - lib/net/scp/errors.rb
@@ -111,9 +101,6 @@ files:
111
101
  - lib/net/scp/version.rb
112
102
  - lib/uri/open-scp.rb
113
103
  - lib/uri/scp.rb
114
- - net-scp-public_cert.pem
115
- - net-scp.gemspec
116
- - setup.rb
117
104
  homepage: https://github.com/net-ssh/net-scp
118
105
  licenses:
119
106
  - MIT
@@ -127,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
114
  requirements:
128
115
  - - ">="
129
116
  - !ruby/object:Gem::Version
130
- version: '0'
117
+ version: '2.6'
131
118
  required_rubygems_version: !ruby/object:Gem::Requirement
132
119
  requirements:
133
120
  - - ">="
metadata.gz.sig CHANGED
Binary file
@@ -1 +0,0 @@
1
- <!-- After opening the PR, add a changelog.d/<PR number>.<type>.txt fragment (none, change, security, breaking or breaking-security) instead of editing CHANGES.txt; see CONTRIBUTING.md#changelog. -->
@@ -1,18 +0,0 @@
1
- name: Changelog
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, reopened, labeled, unlabeled]
6
-
7
- permissions:
8
- contents: read
9
-
10
- jobs:
11
- changelog:
12
- runs-on: ubuntu-latest
13
- steps:
14
- - uses: actions/checkout@v4
15
- with:
16
- # HEAD is the PR merged into the base branch; HEAD^1 is the base it was merged into.
17
- fetch-depth: 2
18
- - uses: net-ssh/changelogd@v1
@@ -1,25 +0,0 @@
1
- name: CI
2
- on:
3
- pull_request:
4
- push: { branches: master }
5
- permissions:
6
- contents: read
7
- jobs:
8
- test:
9
- runs-on: ubuntu-latest
10
- strategy:
11
- fail-fast: false
12
- matrix:
13
- ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', '4.0', 'ruby-head']
14
- continue-on-error: ${{ matrix.ruby-version == 'ruby-head' }}
15
- steps:
16
- - uses: actions/checkout@v3
17
- - name: Set up Ruby ${{ matrix.ruby-version }}
18
- uses: ruby/setup-ruby@v1
19
- with:
20
- ruby-version: ${{ matrix.ruby-version }}
21
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
22
- - name: Run Tests
23
- run: bundle exec rake test
24
- env:
25
- RUBYOPT: "--enable=frozen_string_literal"
data/.gitignore DELETED
@@ -1,13 +0,0 @@
1
- coverage
2
- pkg
3
- doc
4
- *.swp
5
-
6
- .DS_Store
7
-
8
- # Bundle local files
9
- /vendor/
10
- .bundle/config
11
- Gemfile.lock
12
-
13
- lib/net/ssh/version.rb.old
data/CONTRIBUTING.md DELETED
@@ -1,33 +0,0 @@
1
- # Contributing to net-scp
2
-
3
- Run the tests with `bundle exec rake test`.
4
-
5
- ## Changelog
6
-
7
- Don't edit `CHANGES.txt`. Instead, add a fragment file to `changelog.d/` in your PR; the release's version bump (`rake vbump:*`) moves all fragments into a new `=== <version>` section at the top of `CHANGES.txt` and deletes them.
8
-
9
- A fragment is named `<number>.<type>.txt`, where `<number>` is the PR number (so open the PR first, then add the fragment), and contains a single UTF-8 paragraph: the entry as it should read in `CHANGES.txt`, without the bullet or prefix. Lines are joined, so it can be wrapped. If it doesn't end with a reference list such as `[#95, #101]` or `[GHSA-xxxx-xxxx-xxxx]`, ` [#<number>]` is appended.
10
-
11
- | Type | Written as | Use for |
12
- | ------------------- | ------------------------------ | ------------------------------------------------------------ |
13
- | `breaking-security` | `* BREAKING: Security: <text>` | an incompatible change made for security |
14
- | `breaking` | `* BREAKING: <text>` | an incompatible change |
15
- | `security` | `* Security: <text>` | a security fix or hardening |
16
- | `change` | `* <text>` | any other user-visible fix or feature |
17
- | `none` | nothing | PRs with no user-visible change (tests, CI, docs, refactors) |
18
-
19
- Examples:
20
-
21
- ```sh
22
- rake "changelog:new[102,change,Fixed uploading files with spaces in their names]"
23
- # changelog.d/102.change.txt -> * Fixed uploading files with spaces in their names [#102]
24
-
25
- echo 'Refuse downloads that write outside the target directory [GHSA-xxxx-xxxx-xxxx]' > changelog.d/103.security.txt
26
- touch changelog.d/104.none.txt
27
- ```
28
-
29
- For several entries from one PR add a suffix: `102.change.txt`, `102.change.2.txt` (`changelog:new` picks the next free one).
30
-
31
- `rake changelog:check` validates the fragments and `rake changelog:preview` prints the section the next release would add. CI fails a PR that edits `CHANGES.txt` or doesn't add or modify a `changelog.d/<PR number>.<type>.txt` fragment, unless it only touches `changelog.d/` or a maintainer adds the `skip-changelog` label; Dependabot PRs are skipped.
32
-
33
- The full rules, including how a release orders the entries, are in the [changelogd README](https://github.com/net-ssh/changelogd#readme).
data/Gemfile DELETED
@@ -1,22 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in mygem.gemspec
4
- gemspec
5
-
6
- gem "net-ssh", ">= 7.3.1"
7
- gem "logger" # no longer a default gem in Ruby 4.0+
8
-
9
- # TODO: add to gemspec
10
- gem "bundler", ">= 1.11"
11
- gem "rake", ">= 12.0"
12
- gem "rdoc"
13
-
14
- # git: rather than github:, which Bundler 1.x (the publish workflow uses 1.17.3) expands to an unsupported git:// URL.
15
- gem "changelogd", git: "https://github.com/net-ssh/changelogd.git", tag: "v1", group: :development
16
-
17
- gem 'byebug', group: %i[development test] if !Gem.win_platform? && RUBY_ENGINE == "ruby"
18
-
19
- if ENV["CI"]
20
- gem 'codecov', require: false, group: :test
21
- gem 'simplecov', require: false, group: :test
22
- end
data/Manifest DELETED
@@ -1,17 +0,0 @@
1
- CHANGELOG.rdoc
2
- lib/net/scp/download.rb
3
- lib/net/scp/errors.rb
4
- lib/net/scp/upload.rb
5
- lib/net/scp/version.rb
6
- lib/net/scp.rb
7
- lib/uri/open-scp.rb
8
- lib/uri/scp.rb
9
- Rakefile
10
- README.md
11
- setup.rb
12
- test/common.rb
13
- test/test_all.rb
14
- test/test_download.rb
15
- test/test_scp.rb
16
- test/test_upload.rb
17
- Manifest
data/Rakefile DELETED
@@ -1,185 +0,0 @@
1
- require "rubygems"
2
- require "rake"
3
- require "rake/clean"
4
- begin
5
- require "rdoc/task"
6
- rescue LoadError
7
- end
8
- require "bundler/gem_tasks"
9
-
10
- desc "When releasing make sure NET_SSH_BUILDGEM_SIGNED is set"
11
- task :check_NET_SSH_BUILDGEM_SIGNED do
12
- raise "NET_SSH_BUILDGEM_SIGNED should be set to release" unless ENV['NET_SSH_BUILDGEM_SIGNED']
13
- end
14
-
15
- Rake::Task[:release].enhance [:check_NET_SSH_BUILDGEM_SIGNED]
16
- Rake::Task[:release].prerequisites.unshift(:check_NET_SSH_BUILDGEM_SIGNED)
17
-
18
- task default: ["build"]
19
- CLEAN.include [ 'pkg', 'rdoc' ]
20
- name = "net-scp"
21
-
22
- require_relative "lib/net/scp/version"
23
- version = Net::SCP::Version::CURRENT
24
-
25
- begin
26
- require "changelogd/rake"
27
- rescue LoadError
28
- # A git gem isn't on the load path under plain `rake`, as the release workflow runs it; bundler/setup could clash with the running rake.
29
- require "bundler"
30
- $LOAD_PATH.unshift(*Bundler.definition.specs["changelogd"].flat_map(&:full_require_paths))
31
- require "changelogd/rake"
32
- end
33
- Changelogd::RakeTasks.new(version_file: "lib/net/scp/version.rb")
34
-
35
- namespace :cert do
36
- desc "Update public cert from private - only run if public is expired"
37
- task :update_public_when_expired do
38
- require 'openssl'
39
- require 'time'
40
- raw = File.read "net-scp-public_cert.pem"
41
- certificate = OpenSSL::X509::Certificate.new raw
42
- raise Exception, "Not yet expired: #{certificate.not_after}" unless certificate.not_after < Time.now
43
- sh "gem cert --build netssh@solutious.com --days 365*5 --private-key /mnt/gem/net-ssh-private_key.pem"
44
- sh "mv gem-public_cert.pem net-scp-public_cert.pem"
45
- sh "gem cert --add net-scp-public_cert.pem"
46
- end
47
- end
48
-
49
- if false
50
- begin
51
- require "jeweler"
52
- Jeweler::Tasks.new do |s|
53
- s.version = version
54
- s.name = name
55
- s.summary = "A pure Ruby implementation of the SCP client protocol"
56
- s.description = s.summary
57
- s.email = "net-ssh@solutious.com"
58
- s.homepage = "https://github.com/net-ssh/net-scp"
59
- s.authors = ["Jamis Buck", "Delano Mandelbaum"]
60
-
61
- s.add_dependency 'net-ssh', ">=2.6.5"
62
-
63
- s.add_development_dependency 'test-unit'
64
- s.add_development_dependency 'mocha'
65
-
66
- s.license = "MIT"
67
-
68
- s.signing_key = File.join('/mnt/gem/', 'gem-private_key.pem')
69
- s.cert_chain = ['gem-public_cert.pem']
70
- end
71
- Jeweler::GemcutterTasks.new
72
- rescue LoadError
73
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
74
- end
75
- end
76
-
77
- require 'rake/testtask'
78
- Rake::TestTask.new do |t|
79
- t.libs = ["lib", "test"]
80
- end
81
-
82
- extra_files = %w[LICENSE.txt THANKS.txt CHANGES.txt ]
83
- if defined?(RDoc::Task)
84
- RDoc::Task.new do |rdoc|
85
- rdoc.rdoc_dir = "rdoc"
86
- rdoc.title = "#{name} #{version}"
87
- rdoc.generator = 'hanna' # gem install hanna-nouveau
88
- rdoc.main = 'README.md'
89
- rdoc.rdoc_files.include("README*")
90
- rdoc.rdoc_files.include("bin/*.rb")
91
- rdoc.rdoc_files.include("lib/**/*.rb")
92
- extra_files.each { |file|
93
- rdoc.rdoc_files.include(file) if File.exist?(file)
94
- }
95
- end
96
- end
97
-
98
- def change_version(&block)
99
- Rake::Task["changelog:check"].invoke
100
- version_file = 'lib/net/scp/version.rb'
101
- require_relative version_file
102
- pre = Net::SCP::Version::PRE
103
- tiny = Net::SCP::Version::TINY
104
- result = block[pre: pre, tiny: Net::SCP::Version::TINY]
105
- raise ArgumentError, "Version change logic should always return a pre" unless result.key?(:pre)
106
-
107
- new_pre = result[:pre]
108
- new_tiny = result[:tiny] || tiny
109
- found = { pre: false, tiny: false }
110
- File.open("#{version_file}.new", "w") do |f|
111
- File.readlines(version_file).each do |line|
112
- match =
113
- if pre.nil?
114
- /^(\s+PRE\s+=\s+)nil(\s*)$/.match(line)
115
- else
116
- /^(\s+PRE\s+=\s+")#{pre}("\s*)$/.match(line)
117
- end
118
- if match
119
- prefix = match[1]
120
- postfix = match[2]
121
- prefix.delete_suffix!('"')
122
- postfix.delete_prefix!('"')
123
- new_line = "#{prefix}#{new_pre.inspect}#{postfix}"
124
- puts "Changing:\n - #{line} + #{new_line}"
125
- line = new_line
126
- found[:pre] = true
127
- end
128
-
129
- if new_tiny != tiny
130
- match = /^(\s+TINY\s+=\s+)#{tiny}(\s*)$/.match(line)
131
- if match
132
- prefix = match[1]
133
- postfix = match[2]
134
- new_line = "#{prefix}#{new_tiny}#{postfix}"
135
- puts "Changing:\n - #{line} + #{new_line}"
136
- line = new_line
137
- found[:tiny] = true
138
- end
139
- end
140
-
141
- f.write(line)
142
- end
143
- raise ArgumentError, "Cound not find line: PRE = \"#{pre}\" in #{version_file}" unless found[:pre]
144
- raise ArgumentError, "Cound not find line: TINY = \"#{tiny}\" in #{version_file}" unless found[:tiny] || new_tiny == tiny
145
- end
146
-
147
- FileUtils.mv version_file, "#{version_file}.old"
148
- FileUtils.mv "#{version_file}.new", version_file
149
- Rake::Task["changelog:release"].invoke
150
- end
151
-
152
- namespace :vbump do
153
- desc "Final release"
154
- task :final do
155
- change_version do |pre:, tiny:|
156
- _ = tiny
157
- if pre.nil?
158
- { tiny: tiny + 1, pre: nil }
159
- else
160
- raise ArgumentError, "Unexpected pre: #{pre}" if pre.nil?
161
-
162
- { pre: nil }
163
- end
164
- end
165
- end
166
-
167
- desc "Increment prerelease"
168
- task :pre, [:type] do |_t, args|
169
- change_version do |pre:, tiny:|
170
- puts " PRE => #{pre.inspect}"
171
- match = /^([a-z]+)(\d+)/.match(pre)
172
- raise ArgumentError, "Unexpected pre: #{pre}" if match.nil? && args[:type].nil?
173
-
174
- if match.nil? || (!args[:type].nil? && args[:type] != match[1])
175
- if pre.nil?
176
- { pre: "#{args[:type]}1", tiny: tiny + 1 }
177
- else
178
- { pre: "#{args[:type]}1" }
179
- end
180
- else
181
- { pre: "#{match[1]}#{match[2].to_i + 1}" }
182
- end
183
- end
184
- end
185
- end